Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undo Button In Android Drawing App

So I would like to implement an undo button for a drawing app I am working on for android. My current idea is to put the current draw path into a list of paths on MotionEvent.ACTION_UP. In onDraw(), simply draw everything that is in the list of paths. When the user presses undo, you remove the last drawn path from the list of paths and call invalidate(), forcing onDraw() to be called, which will draw everything in the list of paths. Since we removed the previous path from the list, that path should not be drawn and therefore should be "undone".

The problem I am having is the path never seems to actually be undone. It seems like the logic in my head is correct, but this implementation does not work correctly. Any help will be greatly appreciated.

Here is my code:

DrawingView.java:

Instance variables (to clarify following methods):

private Context context;
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private int previousPaintColor;
private int paintColor;
private float brushSize;
private float eraserSize;
private float lastBrushSize;
private boolean isErasing = false;
private List<Path> moveList = null;
private List<Path> undoList = null;
private List<Path> currentMoveList = null;

Called from constructor:

private void setupDrawing() {
    drawPath = new Path();
    drawPaint = new Paint();

    brushSize = getResources().getInteger(R.integer.default_brush_size);
    lastBrushSize = brushSize;

    drawPaint.setColor(paintColor);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(brushSize);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);

    canvasPaint = new Paint(Paint.DITHER_FLAG);
}

onDraw:

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
    for (Path path : currentMoveList) {
        canvas.drawPath(path, drawPaint);
    }
    for (Path path : moveList) {
        canvas.drawPath(path, drawPaint);   
    }
}

onTouchEvent:

@Override
public boolean onTouchEvent(MotionEvent event) {
    float touchX = event.getX();
    float touchY = event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            drawPath.moveTo(touchX, touchY);
            break;
        case MotionEvent.ACTION_MOVE:
            drawPath.lineTo(touchX, touchY);
            currentMoveList.add(drawPath);
            break;
        case MotionEvent.ACTION_UP:
            drawPath.lineTo(touchX, touchY);
            drawCanvas.drawPath(drawPath, drawPaint);
            moveList.add(drawPath);
            drawPath = new Path();
            currentMoveList.clear();
            break;
        default:
            return false;
    }
    invalidate();
    return true;
}

undo() :

public void undo() {
    if (moveList.size() > 0) {
        undoList.add(moveList.remove(moveList.size() - 1));
        invalidate();   
    }
}

Regards,

Kyle.

like image 698
kformeck Avatar asked Feb 02 '26 20:02

kformeck


1 Answers

After some trial and error, here is the fix:

Remove this line of code:

canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);

from onDraw() method and everything works perfectly :)

like image 164
kformeck Avatar answered Feb 05 '26 10:02

kformeck