I am making a drawing app, and would like to implement an undo function to remove the immediate previous drawn path.
private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points
private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap
public DrawView(Context context, AttributeSet attrs)
{
super(context, attrs); // pass context to View's constructor
this.context_new=context;
paintScreen = new Paint(); // used to display bitmap onto screen
// set the initial display settings for the painted line
paintLine = new Paint();
paintLine.setAntiAlias(true); // smooth edges of drawn line
paintLine.setColor(Color.BLACK); // default color is black
paintLine.setStyle(Paint.Style.STROKE); // solid line
paintLine.setStrokeWidth(5); // set the default line width
paintLine.setStrokeCap(Paint.Cap.ROUND); // rounded line ends
pathMap = new HashMap<Integer, Path>();
previousPointMap = new HashMap<Integer, Point>();
} // end DrawView constructor
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, 0, 0, paintScreen);
for (Integer key : pathMap.keySet())
canvas.drawPath(pathMap.get(key), paintLine);
}
// called when the user finishes a touch
private void touchEnded(int lineID)
{
Path path = pathMap.get(lineID); // get the corresponding Path
bitmapCanvas.drawPath(path, paintLine); // draw to bitmapCanvas
path.reset(); // reset the Path
rememberLineId = lineID;
} // end method touch_ended
//undo
private void undo()
{
Path path = pathMap.get(rememberLineId); // get the corresponding Path
pathMap.remove(rememberLineId);
bitmapCanvas.clearPath(path, paintLine);
path.reset(); // reset the Path
}
However, it seems there is no bitmapCanvas.clearPath
this method? If then how could it be modified?
Declarations:
private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap
private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points
private Bitmap bitmapBackup;
OnSizeChanged
@Override
public void onSizeChanged(int w, int h, int oldW, int oldH)
{
super.onSizeChanged(w, h, oldW, oldH);
DoodlzViewWidth = w;
DoodlzViewHeight = h;
bitmapBackup = Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);
bitmap = Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
bitmap .eraseColor(Color.WHITE); // erase the BitMap with white
bitmapBackup.eraseColor(Color.WHITE);
}
FirsttoBackup method, will invoke when the below TouchedStart performs
public void firsttobackup()
{
bitmapBackup=bitmap;
Toast message = Toast.makeText(getContext(), "backuped 123", Toast.LENGTH_SHORT);
message.show(); //THIS TOAST CAN BE SUCESSFULLY PRESENTED when touching screen starting to draw
}
OnDraw
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, 0, 0, paintScreen);
for (Integer key : pathMap.keySet())
canvas.drawPath(pathMap.get(key), paintLine);
}
OnTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getActionMasked(); // event type
int actionIndex = event.getActionIndex(); // pointer (i.e., finger)
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN)
{
firsttobackup(); //TOAST CAN SHOW "BACKUP 123"
touchStarted(event.getX(actionIndex), event.getY(actionIndex),
event.getPointerId(actionIndex));
}
Undo: user pressing the undo button will invoke this
public void undo()
{
bitmap = bitmapBackup.copy(Bitmap.Config.ARGB_8888, true);
bitmapCanvas = new Canvas(bitmap);
}
A method firsttobackup()
is used now such that bitmapBackup would set = bitmap when executing OnTouchEvent
touchStarted
. I have put a toast in it and it is successfully to be presented "backup 123" when user press the screen and started to draw.
When user clicks undo button, it will invoke the undo
method, but now pressing the undo button, no action can be seen...why?
It is an old post, but I was looking for an answer for that issue as well. I was not satisfied with the chosen answer for that post and I found one myself after that. I actually think that having a full bitmap as a backup is not great memory-wise and it will limit the number of undo steps we can have.
I believe a better solution would be :
To have a stack of paths in your class
private Stack<Path> m_pathHistory = new Stack<Path>();
next to your canvas and your paintbrush (initialization skipped) :
private Canvas m_drawingCanvas;
private Paint m_paint;
Then every time a stroke is finished (on the touch up event), add a "clone" of the path to the undo history:
m_pathHistory.Push(new Path(currentPath));
And here is the undo function :
public void Undo()
{
if(m_pathHistory.Count > 0)
{
m_pathHistory.Pop(); // Remove the last path from the history
m_drawingCanvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear); // Clear the canvas with a transparent color
// Draw the paths which are still in the history
foreach (Path p in m_pathHistory)
{
m_drawingCanvas.DrawPath(p, m_paint);
}
}
}
The paths are much smaller to store in the memory than the full bitmaps, so we can have a much bigger history.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With