1

I have done the code for drawing a line through finger on canvas & also achieved "Undo" kind of functionality. Undo works pretty fine for the lines which doesn't cross each other, but when the lines cross each other & I undo previous line, it affects the another line as well at the "crossed" point, please have a look at the pics

Two Lines crossing each other

Undo clears some part of another line as well

for drawing I used this code

mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(16);
mPaint.setXfermode(null);

//In MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(x, y);

// In MotionEvent.ACTION_MOVE:
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);

// In MotionEvent.ACTION_UP:
mPath.lineTo(mX, mY);
circlePath.reset();
mCanvas.drawPath(mPath, mPaint);
mPath.reset();

Now from ACTION_DOWN to ACTION_UP i keep track of all the x,y coordinates to use them for undo feature & here's how i Undo

mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);

// This helps to have undo kind of effect
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

rest code for ACTION_UP, ACTION_DOWN & ACTION_MOVE is same. so basically i just draw another line on same x-y coordinates with

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

& that results same as marked in pic with red circle.

So how can I only erase the part of particular line only even though they are having same x-y coordinates, can I just convert the drawn lines to ImageView / Bitmap after it's drawn so I can remove the ImageView it-self & it don't affect the another line? Or is there any better way to achieve this?

Sandip Fichadiya
  • 3,430
  • 2
  • 21
  • 47

1 Answers1

0

You can't undo a drawing on a Canvas. From the documentation:

Via the Canvas, your drawing is actually performed upon an underlying Bitmap, which is placed into the window.

One approach to solve your issue could be using a backup Bitmap to save the state of the current Bitmap before drawing on it, for example using a Memento pattern.

Take a look at Fast undo/redo for bitmap editor when memory is limited? and Fast undo facility for bitmap editor application (the last one targetting iPhone, but the underlying idea is the same)

Another approach less memory consuming could be saving the state of the objects that you want to draw on your canvas and draw them on demand.

Community
  • 1
  • 1
antonio
  • 18,044
  • 4
  • 45
  • 61
  • Means after one line is drawn, I need to store the bitmap before ACTION_DOWN happens & in undo, i should set that bitmap again to the whole view or something? – Sandip Fichadiya Mar 18 '16 at 17:16
  • Yes, you need to store the previous state in some way. Storing a `Bitmap` before every action can be very memory consuming, maybe it's better to store the state of the events and redraw your `Bitmap` on demand. – antonio Mar 18 '16 at 17:19
  • Sorry but I am not sure about "Storing the state of events", can you please tell that in brief? – Sandip Fichadiya Mar 18 '16 at 17:22
  • Imagine that you want to draw a bunch of lines drawn by the user and you want to be able to undo each line separately. You can store your lines using an structure and all draw the lines from the structure into a Bitmap. When the user undos, you remove your line from the structure and redraw the Bitmap completely (cleaning it and redrawing all the lines from the structure again). To hold the different states of your structure you can use a Memento pattern – antonio Mar 18 '16 at 17:34