Android Canvas中具有撤消/重做操作的自定义画笔

时间:2016-08-17 11:18:57

标签: android android-canvas android-bitmap android-paint

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

enter image description here

现在的问题是,

  1. 撤消,重做操作不起作用,自定义画笔在移动触摸点时反复绘制。

    问:如何进行撤消/重做操作?

  2. 自定义画笔工具不够光滑。现在他们看起来很粗糙和人为。

    Q值。如何使用自定义笔触使绘画变得光滑自然?

  3. enter image description here

    点击此处查看我的示例代码,

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

1 个答案:

答案 0 :(得分:0)

为了使您的画笔看起来“更平滑”,并不是100%确定它的含义,但您需要收紧用于自定义画笔的图像上的点。使它们更紧凑将使边缘看起来更光滑。

对于undo redo,在你的touchUp方法中,你永远不会只将brushBrushMap添加到brushMap中。因此,在提取中没有任何东西可以绘制,因为该地图将始终为空。