0

This Question has been asked many times like Android Drawing, Erasing and Undoing Action But no one has giving the proper solution for it. I am making a drawing app and everything was working fine until i added undo feature. After adding undo feature eraser is not working fine. It makes previous drawing black and don't erase as well. This is my DrawingView Class' constructor:

public DrawingView(Context context){
    super(context);
    // if(!isInEditMode())
    setLayerType(View.LAYER_TYPE_SOFTWARE, drawPaint);

            drawPath = new Path();
    drawPaint = new Paint();
    drawPaint.setColor(paintColor);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(35);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
    canvasPaint = new Paint(Paint.DITHER_FLAG);

}

Here is the onDraw method

@Override
protected void onDraw(Canvas canvas) {
//draw view

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

     for (Path p : paths)
        {
           drawPaint.setColor(colorsMap.get(p));
           drawPaint.setStrokeWidth(widthMap.get(p));
           canvas.drawPath(p, drawPaint);          
        } 
        drawPaint.setColor(paintColor);
        drawPaint.setStrokeWidth(30);

    if(erase){
        return;
    }
    canvas.drawPath(drawPath, drawPaint);
}

and here is touchEvent Handler

@Override
public boolean onTouchEvent(MotionEvent event) {
//detect user touch     
    float touchX = event.getX();
    float touchY = event.getY();
    if(erase){
    //  drawPaint.setColor(paintColor);
        drawCanvas.drawPath(drawPath, drawPaint);
        invalidate();
    }

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
         undonePaths.clear();
           drawPath.reset();

        drawPath.moveTo(touchX, touchY);

        break;
    case MotionEvent.ACTION_MOVE:
         drawPath.lineTo(touchX, touchY);

        break;
    case MotionEvent.ACTION_UP:
        drawCanvas.drawPath(drawPath, drawPaint);
       if(!erase){
        paths.add(drawPath);
        colorsMap.put(drawPath,getDrawingColor());
        widthMap.put(drawPath,30);
       }
        drawPath = new Path();


        break;
    default:
        return false;
    }
    invalidate();
    return true;
}

here is my SetErase method

public void setErase(boolean isErase){
    //set erase true or false    
    erase=isErase;
    if(erase){
        drawPaint.setMaskFilter(null);
        drawPaint.setAlpha(0xFF);
        drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        } 
    else{ drawPaint.setXfermode(null);  
        }
    }

and the last my undo Method

public void onClickUndo() 
{ 
   if (paths.size()>0) 
    { 
       undonePaths.add(paths.remove(paths.size()-1));
       invalidate();
    }      
   else Toast.makeText(getContext(), "nothing more to undo", Toast.LENGTH_SHORT).show();
}

Is there no way to implement undo and erase features together in a drawing app? If yes? then please provide some help. Thanks

Community
  • 1
  • 1
Fahid Nadeem
  • 412
  • 2
  • 7
  • 19

1 Answers1

1

this is my code. I could erase and undo. The only problem that I have is when I go to click on the brush, it continuous erasing. To redraw again have to choose the color (doesn't draw with the last color). If it works and you can fix that let me know, and I hope I helped.

public class DrawingView extends View {
private Context context;
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private int previousPaintColor;
private int paintColor=0xFF000000;
private float brushSize;
private float eraserSize;
private float lastBrushSize;
private boolean isErasing = false;
private boolean isImageLoaded = false;
private List<PaintPathPair> undoList = null;
private List<PaintPathPair> currentMoveList = null;
private List<PaintPathPair> moveList = null;

public DrawingView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    this.moveList = new ArrayList<PaintPathPair>();
    this.undoList = new ArrayList<PaintPathPair>();
    this.currentMoveList = new ArrayList<PaintPathPair>();
    this.canvasPaint = new Paint(Paint.DITHER_FLAG);
    setupDrawing();
}

private void clearBrushes() {
    moveList.clear();
    undoList.clear();
    currentMoveList.clear();
}
private void setupDrawing() {
    drawPath = new Path();
    drawPaint = new Paint();

    brushSize = getResources().getInteger(R.integer.medium_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);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    drawCanvas = new Canvas(canvasBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
    if (isImageLoaded) {
        canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 
    }
    drawPaint.setColor(paintColor);
    for (PaintPathPair pair : currentMoveList) {
        canvas.drawPath(pair.getPath(), pair.getPaint());
    }
    for (PaintPathPair pair : moveList) {
        canvas.drawPath(pair.getPath(), pair.getPaint());   
    }
}
public void startNewDrawing() {
    setBackgroundColor(Color.WHITE);
    drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    clearBrushes();
    isImageLoaded = false;
    invalidate();
}
public void undo() {
    if (moveList.size() > 0) {
        undoList.add(moveList.remove(moveList.size() - 1));
        invalidate();   
    }
}
public void redo() {
    if (undoList.size() > 0) {
        moveList.add(undoList.remove(undoList.size() - 1));
        invalidate();
    }
}
@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(new PaintPathPair(drawPaint, drawPath));
            break;
        case MotionEvent.ACTION_UP:
            drawPath.lineTo(touchX, touchY);
            drawCanvas.drawPath(drawPath, drawPaint);
            moveList.add(new PaintPathPair(new Paint(drawPaint), drawPath));
            drawPath = new Path();
            currentMoveList.clear();
            break;
        default:
            return false;
    }
    invalidate();
    return true;
}

void setErasing(boolean erasing) {
    this.isErasing = erasing;
    int colorToSet = 0;
    previousPaintColor = drawPaint.getColor();

    if(isErasing) {
        //drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        this.setColor("#FFFFFFFF");
    }
    else {
        drawPaint.setXfermode(null);
    }
}
public void setColor(String newColor) {
    this.previousPaintColor = drawPaint.getColor();
    paintColor = Color.parseColor(newColor);
    drawPaint.setColor(paintColor);
    invalidate();
}
public float getBrushSize() {
    return brushSize;
}
public void setBrushSize(float newSize) {
    brushSize = newSize;
    drawPaint.setStrokeWidth(brushSize);
    setErasing(false);
}
public float getEraserSize() {
    return eraserSize;
}
public void setEraserSize(float newSize) {
    eraserSize = newSize;
    drawPaint.setStrokeWidth(eraserSize);
    setErasing(true);
}
public void setLastBrushSize(float lastBrushSize) {
    this.lastBrushSize = lastBrushSize;
}
public void setBackgroundImage(Bitmap image) {
    isImageLoaded = true;
    clearBrushes();
    canvasBitmap = image;
    drawCanvas.drawBitmap(image, new Matrix(), null);
    invalidate();
}
public float getLastBrushSize() {
    return lastBrushSize;
}   
}
Pablo Villar
  • 177
  • 1
  • 15