在Android绘图应用程序中实现橡皮擦 - 黑色轨迹然后透明

Sco*_*ott 16 android android-canvas eraser

我有一个Android的绘图应用程序,我目前正在尝试添加一个真正的橡皮擦.在此之前,我刚刚使用白色涂料作为橡皮擦,但现在我不再使用背景颜色和图像了.我通过透明画布下方的图像视图来完成此操作.

我面临的问题是每当我启用我的橡皮擦时,它会在我用手指向下时画出一条坚实的黑色痕迹,但是一旦我释放它就会变成透明的.请参见下面的屏幕截图:

这是我的手指在屏幕上时的样子 - 一条坚实的黑色小道 当我的手指仍然在屏幕上时,它看起来如何

这是我从屏幕上移开手指后的样子 一旦我放手,它看起来如何

所以,我似乎越来越接近了,但是当我的手指在擦除时触摸时,我无法找到正确的设置组合以避免黑色痕迹.以下是一些相关的代码片段:

的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);
}
Run Code Online (Sandbox Code Playgroud)

的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;
}
Run Code Online (Sandbox Code Playgroud)

当前尝试橡皮擦设置

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);
}
Run Code Online (Sandbox Code Playgroud)

还有其他一些关于橡皮擦的帖子,但大多数都只是说要使用PorterDuff.Mode.CLEAR,setMakFilter(null)这应该有效.就我而言,它没有.无论我尝试什么,我首先得到黑色的痕迹,然后在我释放后才得到所需的结果.

如有必要,我可以提供更多代码.

Sim*_*uis 14

我建议你阅读FingerPaint.java的官方样本
它完全符合你在这里想要实现的目标.

要在删除内容时不显示跟踪,请查看onDraw()方法和eraserMode变量:

@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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不你不是.在这个例子中,在onDraw方法中有两个`Canvas`用于渲染视图,另一个用于在视图外部渲染绘图. (3认同)
  • 好吧,所以你需要做```mCanvas.drawPath(mPath,mPaint);```每次你在eraserMode并且发生触摸事件.这将修改渲染器位图.并且在调用此方法后不要忘记调用invalidate. (2认同)

Fah*_*eem 10

人们仍然在寻找一种更短的方法来删除那条黑线.只需setLayerType(View.LAYER_TYPE_SOFTWARE, drawPaint);将此行添加到构造函数中即可.干杯!


Rak*_*dav 7

上述答案都不适合我。经过一番尝试和一些逻辑,解决了,检查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;
}
Run Code Online (Sandbox Code Playgroud)

和这个

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