Android - User paints lines with their finger

2019-05-27 11:39发布

问题:

I want to build a tool on Android where the user can paint some simple objects over a picture (eg line, circle or arrow). I started trying the line part first, and indeed I could succeed on painting it. The logic is that the user taps at one point and then drags their finger, painting the line. I use a class like this (it is based on DonGru's answer here):

public class DrawView extends View {
    Paint paint = new Paint();
    float Sx, Sy, Lx, Ly;

    public DrawView(Context context, float x1, float y1, float x2, float y2) {
        super(context);

        paint.setColor(Color.RED);
        Sx=x1;
        Sy=y1;
        Lx=x2;
        Ly=y2;   
    }

    @Override
    public void onDraw(Canvas canvas) {
            canvas.drawLine(Sx, Sy, Lx, Ly, paint);
    }
}

From the activity code I use the onTouch listener like this:

@Override
public boolean onTouch(View view, MotionEvent event) { 
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Sx1 = event.getX();
            Sy1 = event.getY();
            return true;

        case MotionEvent.ACTION_MOVE:
            Cx1 = event.getX();
            Cy1 = event.getY();
            drawLine();
            return true;

        case MotionEvent.ACTION_UP:
            Lx1 = event.getX();
            Ly1 = event.getY();
            return true;
        }
    return false;
}

public void drawLine(){

    setContentView(R.layout.show);
    ImageView myImage = (ImageView) findViewById(R.id.lastphoto);
    myImage.setImageBitmap(rotatedPic);

    dv=new DrawView(this, Sx1, Sy1, Cx1, Cy1);

    addContentView(dv, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
            ViewGroup.LayoutParams.FILL_PARENT));

    RelativeLayout mRelativeLayout = (RelativeLayout) findViewById(R.id.linear);
    mRelativeLayout.setOnTouchListener((OnTouchListener) this);
    mRelativeLayout.addView(new Drawer(this));   
}

On every move I recreate the whole view, so that only one line from the starting to ending point is visible. My first concern is that I do not know if this implementation is correct. Also, I want these lines to be handled as objects after created. The user should be able to move them, rotate them, delete etc. I think that I can do this by holding the coordinates of the edges of each line in something like a buffer, and if the user taps very close to one edge I can handle that gesture. But all of this sounds too complex and I do not know if this is unstable.

Is there some different method that I should use to implement something like this that I am totally missing?

回答1:

To store the lines drawn, and enable the user to manipulate them, is only moderately complex, in my opinion.

Create a Line class. Include the start and end co-ordinates, colour etc as fields of the class and methods to delete, move etc. Also add a method which takes a MotionEvent argument. In this method, you use the MotionEvent to determine if this line has been touched and adjust it's position as you need.

Store references to each line drawn (created as an instance of the Line class) in a collection or list of some sort in your extended View class, ArrayList should do. Then, in the onTouch event, call the touch detect method of each line and pass the MotionEvent to the methods.

Finally, override the onDraw callback of the View to draw each line by iterating through the collection of references to the Line instances.

You could also add more gesture such as long press for delete etc. Here's a (totally untested, written from memory) skeleton of such an approach.

class Line

    public float x1, x2, y1, y2;

    public void detectTouch(MotionEvent motionEvent){

         // code to detect a touch and adjust the x and ys accordingly

    }

class DrawView extends View{

    private ArrayList<Line> lines = new ArrayList<Lines>();

    ....
    ....

@Override
public void onDraw(Canvas canvas) {

    super.onDraw();

    for (Line line : lines){
         canvas.drawLine(line.x1,line.y1,line.x2,line.y2);
    }
}

@Override
public boolean onTouch(View view, MotionEvent event) {

    ....
    ....

    for (Line line : lines){
        line.detectTouch(MotionEvent);
    }


}

Have fun!