2016-08-17 81 views
0

我想使用自定義畫筆&撤消/重做操作實現畫布繪製應用程序。首先,我的代碼完美工作,無需使用自定義畫筆(包括撤消/重做操作)。根據這個答案How to make custom brush for canvas in android?我用簡單的圖像尖峯進行位圖繪製。在Android Canvas中使用撤銷/重做操作的自定義畫筆

enter image description here

現在的問題是,

  1. 撤銷,重做操作不工作,自定義畫筆油漆了一遍又一遍,只要移動觸摸點。

    問:如何使撤銷/重做操作起作用?

  2. 自定義的刷子不光滑,因爲他們應該。現在他們看起來粗糙和人造。

    問:如何使用自定義畫筆筆觸使畫面變得平滑自然?

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

回答

0

爲了讓您刷一下「平滑」不是100%肯定是什麼意思,但你將需要收緊用於定製筆刷的圖像上的點。使它們更緊湊會使邊緣看起來更平滑。

至於undo redo,在你的touchUp方法中你永遠不會只添加到customBrushMap中brushMap。所以在繪製中沒有任何東西可以繪製,因爲那張地圖總是空的。

+0

在onDraw()中的for(Vector2 pos:customBrushMap.get(p)){ canvas.drawBitmap(mBitmapBrush,pos.x,pos.y,null); }循環再次覆蓋路徑,使路徑繪製兩次。我怎樣才能畫出一條路徑?如果沒有循環,就無法從verctor2列表中獲取x和y座標。 –

+0

我看到的唯一的事情就是在你的其他地方,你會調用drawPath兩次。 – Ben

+0

您可以運行一次代碼來檢查我正在談論的問題嗎? –