2

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?

Community
  • 1
  • 1
george
  • 1,366
  • 5
  • 22
  • 38
  • Your implementation is weird. For implementing such a program, you need a `View`, override its `onDraw` method, handle user's drag motions, and call `View.invalidate()` accordingly. – neevek May 17 '12 at 16:03
  • You mean to create an object that extends view? Like DrawView which I have as the class that draws? But calling invalidate on an instance of this object does not erase former lines. Do you have a link to some example so that I can understand what you mean? – george May 17 '12 at 16:13

1 Answers1

5

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!

Simon
  • 14,029
  • 6
  • 43
  • 60