12

I have a custom layout to draw a line based on touch input. I have it drawing the line but when the user touches the screen, the line disapeers and it draws a new line. What I want it to do is to draw a new line and leave the previous line there. Here is my code:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;

    public class DrawView extends View {
      Paint paint = new Paint();
      float startX;
      float startY;
      float stopX;
      float stopY;

      public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);

        paint.setAntiAlias(true);
        paint.setStrokeWidth(6f);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
      }

      @Override
      protected void onDraw(Canvas canvas) {
          canvas.drawLine(startX, startY, stopX, stopY, paint);
      }

      @Override
              public boolean onTouchEvent(MotionEvent event) {

       switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = event.getX();
            startY = event.getY();
          return true;
        case MotionEvent.ACTION_MOVE:
          stopX = event.getX();
          stopY = event.getY();
         break;
        case MotionEvent.ACTION_UP:    
            stopX = event.getX();
            stopY = event.getY();
          break;
        default:
          return false;
        }
          Invalidate();
        return true;
      }
    } 
Caleb Bramwell
  • 1,332
  • 2
  • 12
  • 24

1 Answers1

18

You need to store all the lines instead of just the last one.
The following code is completely untested, but hopefully gives you the general idea.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;

class Line {
  float startX, startY, stopX, stopY;
  public Line(float startX, float startY, float stopX, float stopY) {
    this.startX = startX;
    this.startY = startY;
    this.stopX = stopX;
    this.stopY = stopY;
  }
  public Line(float startX, float startY) { // for convenience
    this(startX, startY, startX, startY);
  }
}

public class DrawView extends View {
  Paint paint = new Paint();
  ArrayList<Line> lines = new ArrayList<Line>();

  public DrawView(Context context, AttributeSet attrs) {
    super(context, attrs);

    paint.setAntiAlias(true);
    paint.setStrokeWidth(6f);
    paint.setColor(Color.BLACK);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    for (Line l : lines) {
      canvas.drawLine(l.startX, l.startY, l.stopX, l.stopY, paint);
    }
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      lines.add(new Line(event.getX(), event.getY()));
      return true;
    }
    else if ((event.getAction() == MotionEvent.ACTION_MOVE ||
        event.getAction() == MotionEvent.ACTION_UP) &&
        lines.size() > 0) {
      Line current = lines.get(lines.size() - 1);
      current.stopX = event.getX();
      current.stopY = event.getY();
      invalidate();
      return true;
    }
    else {
      return false;
    }
  }
}
tom
  • 21,844
  • 6
  • 43
  • 36
  • thanks. One problem is it is redrawing the canvas every now and again. How do I stop is from redrawing the canvas? – Caleb Bramwell May 26 '13 at 06:22
  • Not sure I understand... isn't the canvas supposed to get redrawn? I had a small mistake in my code (`ACTION_UP` was `ACTION_MOVE`) which I fixed within the 5-minute grace period. Maybe you got the incorrect version? – tom May 26 '13 at 08:01
  • How can i resize the particular line? – Sai Aditya Mar 11 '15 at 08:18
  • 1
    If the lines are all connected it's better to use a Path: `Path path = new Path(); path.moveTo(0, 0); path.lineTo(0,50); path.lineTo(100,50); path.lineTo(100, 0); path.close();` – Jorge Arimany Sep 11 '15 at 10:53
  • Creating new Path on every touch is making app slow.How can avoid this issue? – Muhammad Umair Shafique Mar 15 '16 at 07:39
  • Thanks, How can we restrict line to be straight only ? and add a Target line like a big plus symbol which shows where cursor is located. – Faizan Haidar Khan Jun 17 '21 at 15:23
  • 2
    @FaizanHaidarKhan You should ask a separate question (ideally with what you've already tried). Some hints: Horizontal lines have the same startY and stopY, while vertical lines have the same startX and stopX. So to make the current line horizontal, you could use `current.stopX = event.getX(); current.stopY = current.startY;`. To determine whether the user wants the current line to be horizontal or vertical, you could compare the event's coordinates to the start coordinates and choose the axis that has the greatest difference. – tom Jun 19 '21 at 04:41
  • 1
    @FaizanHaidarKhan For the target symbol, you could store the most recent touch coordinates in instance variables (like the instance variables `paint` and `lines`) and use those coordinates to draw the symbol in the onDraw() method. You'll probably need to add a flag to remember whether the user's finger is currently down or not, and only draw the symbol if the user's finger is down. – tom Jun 19 '21 at 04:41