Android FingerPaint Undo/Redo实现

And*_*oid 8 android paint android-view

我正在开发一个测试项目,类似于FingerPaintAndroid SDK演示中的示例.我试图在我的项目中实现撤消/重做功能,但我尝试的东西并没有像我期望的那样工作.我在互联网和这里找到了一些与此类似的问题,但是他们没有帮助我,这就是我问一个新问题的原因.

以下是我正在做的事情:

    public class MyView extends View {

    //private static final float MINP = 0.25f;
    //private static final float MAXP = 0.75f;



    private Path    mPath;
    private Paint   mBitmapPaint;

    public MyView(Context c) {
        super(c);

        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

        mCanvas = new Canvas(mBitmap);
        mCanvas.drawColor(Color.WHITE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);
    }

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

    private void touch_start(float x, float y) {
        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
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(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;
    }
}
Run Code Online (Sandbox Code Playgroud)

任何建议/想法/例子,这是在我的项目上实现这种功能的最佳方式?

cai*_*ci2 11

我不知道这是不是你的想法,但这就是我的做法.您可以存储一个包含所有路径的数组,而不是将其存储在一个路径中,这样用户可以绘制多条线,只需稍加修改即可添加多点触控.

要进行撤消和重做,只需从paths变量中删除或添加最后一个路径路径,然后将它们存储在新数组中.就像是:

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 
}
Run Code Online (Sandbox Code Playgroud)

这是我修改过的面板,我现在无法尝试,但上面的方法应该可行!希望能帮助到你!(几乎没有额外的变量只是删除它们:)

private ArrayList<Path> undonePaths = new ArrayList<Path>(); 
public class DrawingPanel extends View implements OnTouchListener {

private Canvas  mCanvas;
private Path    mPath;
private Paint   mPaint,circlePaint,outercirclePaint;   
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>(); 
private float xleft,xright,xtop,xbottom;

public DrawingPanel(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);

    this.setOnTouchListener(this);


    circlePaint = new Paint();
    mPaint = new Paint();
    outercirclePaint = new Paint();
    outercirclePaint.setAntiAlias(true);
    circlePaint.setAntiAlias(true);
    mPaint.setAntiAlias(true);        
    mPaint.setColor(0xFFFFFFFF);
    outercirclePaint.setColor(0x44FFFFFF);
    circlePaint.setColor(0xAADD5522);
    outercirclePaint.setStyle(Paint.Style.STROKE);
    circlePaint.setStyle(Paint.Style.FILL);        
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(6);
    outercirclePaint.setStrokeWidth(6);        
    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);             


    cx = 400*DrawActivity.scale;
    cy = 30*DrawActivity.scale;
    circleRadius = 20*DrawActivity.scale;
    xleft = cx-10*DrawActivity.scale;
    xright = cx+10*DrawActivity.scale;
    xtop = cy-10*DrawActivity.scale;
    xbottom = cy+10*DrawActivity.scale;

}


public void colorChanged(int color) {
    mPaint.setColor(color);
}


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

    @Override
    protected void onDraw(Canvas canvas) {            

        for (Path p : paths){
            canvas.drawPath(p, mPaint);
        }

    }

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

    private void touch_start(float x, float y) {
        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            
        mPath = new Path();
        paths.add(mPath);
    }



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

      switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
              if (x <= cx+circleRadius+5 && x>= cx-circleRadius-5) {
                  if (y<= cy+circleRadius+5 && cy>= cy-circleRadius-5){
                      paths.clear();
                      return true;
                      }
              }
              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;
}




}
Run Code Online (Sandbox Code Playgroud)