如何在画布绘画中实现撤销功能后更改绘画颜色/笔触

5

我的绘画应用程序中实现了撤消功能,并且它运行良好。 但是,如果我更改了画笔颜色或画笔笔划,则所有以前绘制的路径都会更改为新的绘画颜色。 代码如下:

public class CustomView extends View implements OnTouchListener {
    public Canvas mCanvas;
    private Path mPath;
    public Paint mPaint, mBitmapPaint;
    Bitmap mBitmap;
    Canvas canvas;
    public ArrayList<Path> paths = new ArrayList<Path>();
    public ArrayList<Path> undonePaths = new ArrayList<Path>();

    private Bitmap im;

    public CustomView(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);
        setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
        mCanvas = new Canvas();
        mPath = new Path();

        im = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
        DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
        int w = metrics.widthPixels;
        int h = metrics.heightPixels;
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        // mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // mPath = new Path();
        // canvas.drawPath(mPath, mPaint);
        canvas.drawColor(Color.TRANSPARENT);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        for (Path p : paths) {
            canvas.drawPath(p, mPaint);
        }
        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        undonePaths.clear();
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        paths.add(mPath);
        mPath = new Path();

    }

    public void onClickUndo() {
        if (paths.size() > 0) {
            undonePaths.add(paths.remove(paths.size() - 1));
            invalidate();
        } else {

        }
        // toast the user
    }

    public void onClickRedo() {
        if (undonePaths.size() > 0) {
            paths.add(undonePaths.remove(undonePaths.size() - 1));
            invalidate();
        } else {

        }
        // toast the user
    }

    @Override
    public boolean onTouch(View arg0, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    }
}

1
撤销操作后,您应该调用invalidate()函数,并使用参数指定将要更新的屏幕部分。现在您调用了没有参数的invalidate()函数,这会导致整个屏幕更新,因此之前触摸的颜色也会改变。 - Onur A.
1个回答

1
这是一个老问题,但我想留下一个答案给来这里的任何人。解决方案是为每个笔画跟踪单独的Paint实例(每个Path对象应该恰好有1个Paint对象)。
将你的touch_up方法更改为不仅重置mPath,还重置mPaint。
private void touch_up() {
    mPath.lineTo(mX, mY);
    mCanvas.drawPath(mPath, mPaint);
    paths.add(mPath);
    mPath = new Path();
    mPaints.add(mPaint)
    // Creates a new Paint reference, but keeps the previous state (color, width, etc.)
    mPaint = new Paint(mPaint);
}

那么您的onDraw方法大致如下。
for (int i = 0; i < mPaths.size(); i++) {
    canvas.drawPath(mPaths.get(i), mPaints.get(i));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接