0

我想用自定义画笔和撤消/重做操作来实现一个画布绘图应用程序。首先,我的代码在不使用自定义画笔(包括撤消/重做操作)的情况下完美运行。根据这个答案How to make custom brush for canvas in android? 我使用简单的图像尖峰进行位图绘制。

在此处输入图像描述

现在的问题是,

  1. 撤消,重做操作不起作用,每当移动触摸点时,自定义画笔一遍又一遍地绘制。

    问:如何使撤消/重做操作起作用?

  2. 定制的刷子炉子并不像他们应该的那样光滑。现在它们看起来很粗糙和做作。

    Q. 如何使用自定义笔触使绘画流畅自然?

在此处输入图像描述

在这里查看我的示例代码,

public class DrawingView extends View {

    private Context ctx;

    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>();

    private Map<Path, Float> brushMap = new HashMap<Path, Float>();
    private Map<Path, List<Vector2>> customBrushMap = new HashMap<Path, List<Vector2>>();
    
    private Bitmap mBitmapBrush;
    private Vector2 mBitmapBrushDimensions;
    private List<Vector2> mPositions = new ArrayList<Vector2>(100);
    private boolean isCustomBrush = false;

    private int selectedColor;
    private float brushSize, lastBrushSize;

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

    private Path drawPath;
    private Paint drawPaint, canvasPaint;
    private int paintColor = 0xFF660000, paintAlpha = 255;
    private Canvas drawCanvas;
    private Bitmap canvasBitmap;

    private static final class Vector2 {
        public Vector2(float x, float y) {
            this.x = x;
            this.y = y;
        }

        public final float x;
        public final float y;
    }

    public DrawingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        ctx = context;
        setupDrawing();
    }

    private void setupDrawing() {
        brushSize = getResources().getInteger(R.integer.small_size);
        lastBrushSize = brushSize;

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

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

    private void touch_start(float x, float y) {
        undonePaths.clear();
        drawPath.reset();
        drawPath.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) {
            drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
        customBrushMap.put(drawPath, mPositions);
    }

    private void touch_up() {
        drawPath.lineTo(mX, mY);
        drawCanvas.drawPath(drawPath, drawPaint);
        paths.add(drawPath);
        brushMap.put(drawPath, brushSize);
        drawPath = new Path();
        drawPath.reset();
        invalidate();
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        //detect user touch
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                if (isCustomBrush) {
                mPositions.add(new Vector2(x - mBitmapBrushDimensions.x / 2, y - mBitmapBrushDimensions.y / 2));
                }
                touch_move(x, y);
                invalidate();
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }

        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        for (Path p : paths) {

        drawPaint.setColor(colorsMap.get(p));
        drawPaint.setShader(shaderMap.get(p));
        drawPaint.setStrokeWidth(brushMap.get(p));
        drawPaint.setAlpha(opacityMap.get(p));

        if (isCustomBrush) {
            if (customBrushMap.get(p) != null) {
                for (Vector2 pos : customBrushMap.get(p)) {
                    Paint paint = new Paint();
                    ColorFilter filter = new PorterDuffColorFilter(selectedColor, PorterDuff.Mode.SRC_IN);
                    paint.setColorFilter(filter);
                    canvas.drawBitmap(mBitmapBrush, pos.x, pos.y, paint);
                }
            }
        } else {
            canvas.drawPath(p, drawPaint);
            drawPaint.setColor(selectedColor);
            drawPaint.setStrokeWidth(brushSize);
            canvas.drawPath(drawPath, drawPaint);
        }
    }
        canvas.restore();
    }

    public void setCustomBrush(Activity activity, String customBrush) {
        isCustomBrush = true;
        invalidate();
        int patternID = getResources().getIdentifier(customBrush, "drawable", "com.androidapp.drawingstutorial");
        mBitmapBrush = BitmapFactory.decodeResource(getResources(), patternID);
        mBitmapBrushDimensions = new Vector2(mBitmapBrush.getWidth(), mBitmapBrush.getHeight());
    }
}
4

1 回答 1

0

To make your brush look "smoother" not 100% sure what is meant by that, but you would need to tighten up the dots on the image you are using for your custom brush. Making them more compact will make the edges look smoother.

As for undo redo, in your touchUp method your never adding to customBrushMap only brushMap. So in the ondraw there is nothing to draw since that map will always be empty.

于 2016-08-17T11:31:50.297 回答