Implementing an eraser in an Android drawing app - black trail and then transparent

一曲冷凌霜 提交于 2019-11-30 12:04:37

问题


I have an drawing app for Android and I am currently trying to add a real eraser to it. Before, I had just used white paint for an eraser, but that won't do anymore since now I allow background colors and images. I do this by having an image view underneath my transparent canvas.

The problem that I am facing is that whenever I enable my eraser, it draws a solid black trail while I have my finger down, but once I release it goes to transparent. See the screen shots below:

This is how it looks while my finger is on the screen - a solid black trail

This is what it looks like once I remove my finger from the screen

So, it seems like I am getting close, but I can't find the right combination of settings to avoid the black trail while my finger is touching while erasing. Here are some relevant code snippets:

onDraw

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawColor(Color.TRANSPARENT);
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    canvas.drawPath(mPath, mPaint);
    canvas.drawPath(mPreviewPath, mPaint);
}

onTouchEvent

@Override
public boolean onTouchEvent(MotionEvent event) {
    float currentX = event.getX();
    float currentY = event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchStart(currentX, currentY);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(currentX, currentY);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touchUp(currentX, currentY);
            invalidate();
            break;
    }
    return true;
}

Current attempt at eraser settings

public void startEraser() {
    mPaint.setAlpha(0);
    mColor = Color.TRANSPARENT;
    mPaint.setColor(Color.TRANSPARENT);
    mPaint.setStrokeWidth(mBrushSize);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setMaskFilter(null);
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    mPaint.setAntiAlias(true);
}

There are several other posts about erasers, but most of them just say to use PorterDuff.Mode.CLEAR, setMakFilter(null) and that that should work. In my case, it doesn't. No matter what I try, I get the black trail first and then the desired result only after I release.

I can provide more code if necessary.


回答1:


I could suggest you to read the official sample of FingerPaint.java
It exactly matches what you are trying to achieve here.

To not show the trail when you erase content, take a look at the onDraw() method and the eraserMode variable:

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawColor(0xFFAAAAAA);
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    if (!eraserMode) {
        canvas.drawPath(mPath, mPaint);
    }
}

boolean eraserMode = false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    eraserMode = false;
    mPaint.setXfermode(null);
    mPaint.setAlpha(0xFF);
    switch (item.getItemId()) {
        /*...*/
        case ERASE_MENU_ID:
            // Add this line
            eraserMode = true;
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            return true;
        /*...*/
    }
    return super.onOptionsItemSelected(item);
}



回答2:


People Still looking for a shorter way to remove that black line while erasing. Just addsetLayerType(View.LAYER_TYPE_SOFTWARE, drawPaint); this line to the constructor and here you go. Cheers!




回答3:


None of the above answers, worked properly for me. After some hit and trial, and some logics as well, solved it, check the ACTION_MOVE

@Override
public boolean onTouchEvent(MotionEvent event) {

    float touchX = event.getX();
    float touchY = event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isEdited = true;
            drawPath.moveTo(touchX, touchY);
            break;
        case MotionEvent.ACTION_MOVE:
            if(isEraser) {
                drawPath.lineTo(touchX, touchY);
                drawCanvas.drawPath(drawPath, drawPaint);
                drawPath.reset();
                drawPath.moveTo(touchX, touchY);
            } else {
                drawPath.lineTo(touchX, touchY);
            }
            break;
        case MotionEvent.ACTION_UP:
            drawCanvas.drawPath(drawPath, drawPaint);
            drawPath.reset();
            break;
        default:
            return false;
    }

    invalidate();
    return true;
}

and this

public void setEraser(boolean isEraser) {
    this.isEraser = isEraser;
    if (isEraser) {
        drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    } else {
        drawPaint.setXfermode(null);
    }
}



回答4:


Can you comment canvas.drawPath(mPreviewPath, mPaint) line and see if it works:

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawColor(Color.TRANSPARENT);
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    canvas.drawPath(mPath, mPaint);
    //canvas.drawPath(mPreviewPath, mPaint);
}



回答5:


when you want make eraser set painting color same as color of canvas not transparent in real life. in android we set set paint color as theme color of canvas mostly either white or black.

mColor = Color.BLACK;
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(mBrushSize);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);


来源:https://stackoverflow.com/questions/25094845/implementing-an-eraser-in-an-android-drawing-app-black-trail-and-then-transpar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!