Search code examples
androidandroid-canvaspointontouchlistener

How to get touch for specific item in canvas point


I have canvas and 3 points that I want to drag on touch event. Here is my code.

public class Canvas7 extends View {

    Paint p;
    PointF point1;
    PointF point2;
    PointF point3;

    public Canvas7(Context context) {
        super(context);
        p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setStrokeWidth(3);

        point1 = new PointF(150, 200);
        point2 = new PointF(150, 500);
        point3 = new PointF(250, 300);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);

        p.setStyle(Paint.Style.FILL);
        p.setColor(Color.GREEN);

        canvas.drawCircle(point1.x, point1.y, 10, p);

        p.setStyle(Paint.Style.FILL);
        p.setColor(Color.BLUE);
        canvas.drawCircle(point2.x, point2.y, 10, p);
        canvas.drawCircle(point3.x, point3.y, 10, p);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        if (x > 0 && y > 0) {
            if ((x < (point1.x + 20) && x > (point1.x - 20)) && (y < (point1.y + 20)) && y > (point1.y - 20)) {
                invalidateCanvas(event, point1);
            } else if ((x < (point2.x + 20) && x > (point2.x - 20)) && (y < (point2.y + 20)) && y > (point2.y - 20)) {
                invalidateCanvas(event, point2);
            } else if ((x < (point3.x + 20) && x > (point3.x - 20)) && (y < (point3.y + 20)) && y > (point3.y - 20)) {
                invalidateCanvas(event, point3);
            }
        }

        return true;
    }

    private void invalidateCanvas(MotionEvent event, PointF point) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            point.set(event.getX(), event.getY());
            invalidate();
        }
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            point.set(event.getX(), event.getY());
            invalidate();
        }
        if(event.getAction() == MotionEvent.ACTION_UP) {
            invalidate();
        }
    }
}

The code is not working. When I click on point and want to move it, it not moves. When I remove the if((point.x) == x || (point.y) == y) check I can move the point, but when I remove the check all points move together. So I want to drag only one point. For example if I touch on point1, I want to move only point1 and nothing more. When I click on point2 I want to move only point2.

How can I do that?


Solution

  • Your code basically fine if you have 1 pixel size fingers and you are able to touch the exact position where you placed a point. :)

    So, you have to introduce a logical area around points and working with them. For example a circle is a good representation for points. If you touch the screen and you get the x, y coordinates, you just have to check which point is the closest one and also check the distance.

    Steps:

    1. If event.getAction() == MotionEvent.ACTION_DOWN is true:

      • You would check which point is the closest one within 10dp (radius of the logical circle)
      • If you found it, you would save as last reference point to know which is in moving state
    2. Elseif event.getAction() == MotionEvent.ACTION_MOVE is true:

      • If you have saved reference point which is in moving, then change the point's coordinates and invalidate UI
    3. Elseif event.getAction() == MotionEvent.ACTION_UP is true:

      • You clear the saved reference point, drag ended