Реализация ластика в приложении для рисования Android - черный след, а затем прозрачный

У меня есть приложение для рисования для Android, и в настоящее время я пытаюсь добавить к нему настоящий ластик. Раньше я только что использовал белую краску для ластика, но это больше не будет, поскольку теперь я допускаю цвет фона и изображения. Я делаю это, имея изображение под моим прозрачным холстом.

Проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда я включаю свой ластик, он рисует сплошной черный след, пока я падаю пальцем, но как только я отпущу его, он станет прозрачным. Смотрите снимок экрана ниже:

Вот как это выглядит, когда мой палец находится на экране - сплошной черный след How it looks while my finger is still on the screen

Вот как это выглядит, как только я удаляю палец с экрана How it looks once I let go

Итак, похоже, что я приближаюсь, но я не могу найти правильную комбинацию настроек, чтобы избежать черной тропы, пока мой палец касается при стирании. Вот некоторые соответствующие фрагменты кода:

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;
}

Текущая попытка настройки ластика

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);
}

Есть несколько других сообщений о ластиках, но большинство из них просто говорят, что используют PorterDuff.Mode.CLEAR, setMakFilter(null) и это должно работать. В моем случае это не так. Независимо от того, что я пытаюсь, я сначала получаю черный след, а затем желаемый результат только после того, как я выпущу.

Я могу предоставить больше кода, если это необходимо.

Ответ 1

Я мог бы предложить вам прочитать официальный образец 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);
}

Ответ 2

Люди Все еще ищут более короткий способ удалить эту черную линию во время стирания. Просто добавьте setLayerType(View.LAYER_TYPE_SOFTWARE, drawPaint); эту строку в конструктор, и вот вы идете. Ура!

Ответ 3

Можете ли вы прокомментировать строку canvas.drawPath(mPreviewPath, mPaint) и посмотреть, работает ли она:

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

Ответ 4

когда вы хотите сделать ластик, установите цвет живописи так же, как цвет холста, который не прозрачен в реальной жизни. в андроиде мы устанавливаем цвет набора цветов как цвет темы холста, в основном белый или черный.

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

Ответ 5

Ни один из вышеперечисленных ответов не работал корректно для меня. После некоторых хитов и испытаний, а также некоторых логик, решив его, проверьте 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;
}

и этот

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