How to draw a lines between points and pull those

2019-02-09 05:12发布

问题:

I want to draw the lines between points on the view, and then pull those points upto desired positions even the shape will change.

i know how to draw the line between two points canvas.drawLine(10, 10, 90, 10, paint); by using this i can draw the lines between points.

EDIT : here i am attaching image for clear explanation, from Paul answer now i am able to draw the lines between points, still have the problem of pulling points...

回答1:

Here's how it's done. Suppose you have your points, make these global:

PointF topLeft = new PointF(10,10);
PointF topRight = new PointF(90,10);
PointF bottomLeft = new PointF(10,90);
PointF bottomRight = new PointF(90,90);

What you need to do is make a RectF around each point. The bigger the RectF, the bigger the touch area for the point is.

float sizeOfRect = 5f;
RectF topLeftTouchArea = new RectF(topLeft.x - sizeOfRect, topLeft.y - sizeOfRect, topLeft.x + sizeOfRect, topLeft.y + sizeOfRect);
//Do this for the other points too

Define some globals to keep track of what the user is doing in onTouch. One int is the corner being touched, and the other four are identifiers for the corners.

private final int NONE = -1, TOUCH_TOP_LEFT = 0, TOUCH_TOP_RIGHT = 1, TOUCH_BOT_LEFT = 2, TOUCH_BOT_RIGHT = 3;
int currentTouch = NONE;

Now, in your onTouch event, you can check which point your user is touching in like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    //The user just put their finger down.
    //We check to see which corner the user is touching
    //And set our global, currentTouch, to the appropriate constant.
    case MotionEvent.ACTION_DOWN:
        if (topLeftTouchArea.contains(event.getX(), event.getY()) {
            currentTouch = TOUCH_TOP_LEFT;
        } else if (topRightTouchArea.contains(event.getX(),event.getY()) {
            currentTouch = TOUCH_TOP_RIGHT;
        } else if (botLeftTouchArea.contains(event.getX(),event.getY()) {
            currentTouch = TOUCH_BOT_LEFT;
        } else if (botRightTouchArea.contains(event.getX(), event.getY()) {
            currentTouch = TOUCH_BOT_RIGHT;
        } else {
            return false; //Return false if user touches none of the corners
        }
        return true; //Return true if the user touches one of the corners
    //Now we know which corner the user is touching.
    //When the user moves their finger, we update the point to the user position and invalidate.
    case MotionEvent.ACTION_MOVE:
        switch (currentTouch) {
        case TOUCH_TOP_LEFT:
             topLeft.x = event.getX();
             topLeft.y = event.getY();
             //The bottom left x position has to move with the top left corner
             bottomLeft.x = topLeft.x;
             //The top right y position has to move with the top left corner
             topRight.y = topLeft.y;
             invalidate();
             return true;
        case TOUCH_TOP_RIGHT:
             topRight.x = event.getX();
             topRight.y = event.getY();
             //The top left y position has to move with the top right corner
             topLeft.y = topRight.y;
             //The bottom right x position has to move with the top right corner
             bottomRight.x = topRight.x;
             invalidate();
             return true;
        case TOUCH_BOT_LEFT:
             bottomLeft.x = event.getX();
             bottomLeft.y = event.getY();
             bottomRight.y = bottomLeft.y;
             topLeft.x = bottomLeft.x;
             invalidate();
             return true;
        case TOUCH_BOT_RIGHT:
             bottomRight.x = event.getX();
             bottomRight.y = event.getY();
             topRight.x = bottomRight.x;
             bottomLeft.y = bottomRight.y;
             invalidate();
             return true;
        }
        //We returned true for all of the above cases, because we used the event
        return false; //If currentTouch is none of the above cases, return false

    //Here the user lifts up their finger.
    //We update the points one last time, and set currentTouch to NONE.
    case MotionEvent.ACTION_UP:
        switch (currentTouch) {
        case TOUCH_TOP_LEFT:
             topLeft.x = event.getX();
             topLeft.y = event.getY();
             //The bottom left x position has to move with the top left corner
             bottomLeft.x = topLeft.x;
             //The top right y position has to move with the top left corner
             topRight.y = topLeft.y;
             invalidate();
             currentTouch = NONE;
             return true;
        case TOUCH_TOP_RIGHT:
             topRight.x = event.getX();
             topRight.y = event.getY();
             //The top left y position has to move with the top right corner
             topLeft.y = topRight.y;
             //The bottom right x position has to move with the top right corner
             bottomRight.x = topRight.x;
             invalidate();
             currentTouch = NONE;
             return true;
        case TOUCH_BOT_LEFT:
             bottomLeft.x = event.getX();
             bottomLeft.y = event.getY();
             bottomRight.y = bottomLeft.y;
             topLeft.x = bottomLeft.x;
             invalidate();
             currentTouch = NONE;
             return true;
        case TOUCH_BOT_RIGHT:
             bottomRight.x = event.getX();
             bottomRight.y = event.getY();
             topRight.x = bottomRight.x;
             bottomLeft.y = bottomRight.y;
             invalidate();
             currentTouch = NONE;
             return true;
        }
        return false;
    }
}

What this does is make a rectangle around your point. Imagine drawing boxes around your points in the picture. These are the "touch pads" created by the Rect objects. The size of the rectangle is set by sizeOfRect. In the onTouchEvent, it checks each rectangle object to see if the user's touch is inside the rectangle, signaling an the user trying to touch that point.



回答2:

I think you may be looking for the Path class:

The Path class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves. It can be drawn with canvas.drawPath(path, paint), either filled or stroked (based on the paint's Style), or it can be used for clipping or to draw text on a path.

See this tutorial for examples of canvas.drawPath



回答3:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.View;

public class TestView extends View
{

    private Paint paint;
    private PointF startPoint, endPoint;
    private boolean isDrawing;

    public TestView(Context context)
    {
        super(context);
        init();
    }

    private void init()
    {
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(2);
        paint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        if(isDrawing)
        {
            canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                startPoint = new PointF(event.getX(), event.getY());
                endPoint = new PointF();
                isDrawing = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if(isDrawing)
                {
                    endPoint.x = event.getX();
                    endPoint.y = event.getY();
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if(isDrawing)
                {
                    endPoint.x = event.getX();
                    endPoint.y = event.getY();
                    isDrawing = false;
                    invalidate();
                }
                break;
            default:
                break;
        }
        return true;
    }
}


回答4:

EDIT:

You indeed need to use Path class in android. Sorry I couldn't come up with a code snippet. But here's something to get you started off.

When you draw a line - canvas.drawLine(x1, y1, x2, y2, paint); your starting point is (x1,y1). now, if you need to pull the line from any end, you need to first fix the other end. Say you pull from (x2,y2) . So (x1,y1) becomes constant and you pull from the other end. When using the Path class, first call a moveTo() to this fix point. What it does is it gives a point about which the line has to be moved. Then, you can use the lineTo() call on the touch events to stretch the line accordingly. A lot of tweaking will be needed. But this is what can get you started. Sorry I couldn't come up with a snippet, little short on time. See the documentation of the Path class. You might find some more helpful things.


EDIT:

About adding touch listeners to points:

Suppose you have a line from (x1,y1) to (x2,y2).

Now to get touch listener for a point, you can add an onTouchListener to your whole view.

final View touchView = findViewById(R.id.touchView);
    touchView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
               if(event.getX() == x2 && event.getY() == y2)
               {
                  //you know that you have clicked on the rear end of the line,so now you can do your dragging stuff.
                  if(event.getAction() == MotionEvent.ACTION_DOWN){
                       //you know user has clicked in order to draw
                       //redraw the existing line with black color to remove it
                       paint.setColor(Color.BLACK);
                       canvas.drawLine(x1, y1, x2, y2, paint);
                       //reset the paint object
                       paint.setColor(Color.WHITE); 
                       //now use moveTo() and lineTo() to attain the functionality of dragging on your Path object
                       path.moveTo(x1,y1);
                       path.lineTo(event.getX(),event.getY());
                  }else if(event.getAction() == MotionEvent.ACTION_MOVE){
                       path.lineTo(event.getX(),event.getY());
                  }else if(event.getAction() == MotionEvent.ACTION_UP){
                  }
       }  
               return true;
        }
    });

This is just an idea, I still didn't get the opportunity to test it. I hope it helps.