【问题标题】:Android: Undo function in Painting app not workingAndroid:绘画应用程序中的撤消功能不起作用
【发布时间】:2014-12-21 13:43:18
【问题描述】:

我正在做一个绘画应用,代码如下:

绘图活动

protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
    setContentView(R.layout.coloring_activity3);
    ....

    mv = (MyDrawView2) findViewById(R.id.drawerView);   
    mv.setDrawingCacheEnabled(true);
    Constants.mPaint = new Paint();
    Constants.mPaint.setAntiAlias(true);
    Constants.mPaint.setDither(true);
    Constants.mPaint.setColor(0xFF000000);
    Constants.mPaint.setStyle(Paint.Style.STROKE);
    Constants.mPaint.setStrokeJoin(Paint.Join.ROUND);
    Constants.mPaint.setStrokeCap(Paint.Cap.ROUND);
    Constants.mPaint.setStrokeWidth(Brush_size);

    ....
    case R.id.btn_eraser:
        Constants.mPaint.setXfermode(null);
        Constants.mPaint.setAlpha(0xFF);
        Constants.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        layout_eraser_size.startAnimation(eraser_move_from_bottom_into_screen);
        layout_eraser_size.setVisibility(View.VISIBLE); 
        btn_eraser.setEnabled(false);
        break;

    case R.id.btn_brush:
        layout_brush_btns.startAnimation(brush_move_from_bottom_into_screen);
        layout_brush_btns.setVisibility(View.VISIBLE); 
        btn_brush.setEnabled(false);
        break;

    case R.id.btn_undo:
        Constants.custom_toast(this, "undo", "clicked");
        mv.onClickUndo();
        break;

DrawView2

public class MyDrawView2 extends View 
{
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;
    Context context;

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


    public MyDrawView2(Context c, AttributeSet attrs) 
    {
        super(c, attrs);
        context = c;
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null); // for solely removing the black eraser
    }

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

    @Override
    protected void onDraw(Canvas canvas) 
    {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, Constants.mPaint);
    }

    public void onClickUndo () 
    { 
        if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           invalidate();
        }
        else
        {
            Toast.makeText(getContext(), "nothing to undo", Toast.LENGTH_SHORT).show();  
        }     
    }

    public void onClickRedo ()
    {
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)) ;
           invalidate();
       } 
       else
       {
           Toast.makeText(getContext(), "nothing to redo", Toast.LENGTH_SHORT).show();  
       }

    }

    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);   
        mCanvas.drawPath(mPath, Constants.mPaint);  // commit the path to our offscreen
        paths.add(mPath);   
        Toast.makeText(getContext(), "path added" + paths.size(), Toast.LENGTH_SHORT).show();  
        mPath.reset();  // kill this so we don't double draw
        Constants.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        // mPaint.setMaskFilter(null);
    }

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

问题:

在每个touch_up 上,我添加了一个toast,计算arraylist paths 中的路径数,并且显示正确。但是点击btn_undo后撤消功能不起作用。

如何解决?非常感谢!

【问题讨论】:

  • 你调试了吗?在onClickUndo() 中放置一个断点并检查
  • @Rustam:是的,我已经检查了paths.size()>0 的条件是否有效,并且它已经通过onClickUndo() 中的if 循环。 path.size 已正确减 1,但不知道为什么视图没有失效。

标签: android path paint undo


【解决方案1】:

通过对 onSizeChanged()、onDraw() 和 touch_up() 进行以下更改,我使撤消和重做工作:

public class MyDrawView2 extends View 
{

    private Canvas mCanvas;
    private Path mPath;

    Context context;

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


    public MyDrawView2(Context c, AttributeSet attrs) 
    {
        super(c, attrs);
        context = c;
        mPath = new Path();
        //added
        mCanvas = new Canvas();

    }

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

    }

    @Override
    protected void onDraw(Canvas canvas) 
    {
        super.onDraw(canvas);
         //added
           for (Path p : paths){
               canvas.drawPath(p, Constants.mPaint);
           }


        canvas.drawPath(mPath, Constants.mPaint);

      //removed bitmap ...
    }

    public void onClickUndo () 
    { 
        if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           invalidate();
        }
        else
        {
            Toast.makeText(getContext(), "nothing to undo", Toast.LENGTH_SHORT).show();  
        }     
    }

    public void onClickRedo ()
    {
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)) ;
           invalidate();
       } 
       else
       {
           Toast.makeText(getContext(), "nothing to redo", Toast.LENGTH_SHORT).show();  
       }

    }

    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);   
            mCanvas.drawPath(mPath, Constants.mPaint);  // commit the path to our offscreen
            paths.add(mPath);   
            Toast.makeText(getContext(), "path added" + paths.size(), Toast.LENGTH_SHORT).show();  
            //added
            mPath = new Path();
            //removed 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;
    }
}

【讨论】:

  • 还是一样... undopath.size 已经报减1 但drawView中没有反映
  • 好的 - 所以我得到了重做和撤消工作 - 请参阅上面的编辑答案。
  • 非常感谢您的帮助!!!撤消功能现在运行良好...但是,在绘制第一条线(例如红色)之后,当第二条线为橙色时,一旦触摸屏幕绘制橙色线,第一条红线立即更改为相同橙色。然后在使用橡皮筋时,一旦橡皮筋接触到屏幕,之前绘制的所有线条也会一起消失......即所有之前绘制的线条的颜色都将遵循最后选择的颜色......
  • 这是一个不同的问题。发生这种情况是因为当您执行撤消和重做时,路径会丢失分配的绘画,除非您调用保存的绘画。您可以将绘画映射到路径或创建类以组合路径和绘画。这可能会有所帮助link
  • @pearmak 如果此答案对您有用,请考虑接受它,以便用户可以从答案中受益。谢谢。
猜你喜欢
  • 2013-02-03
  • 2011-12-13
  • 2015-05-19
  • 2015-08-12
  • 1970-01-01
  • 2011-04-26
  • 2015-03-30
  • 2014-05-26
  • 1970-01-01
相关资源
最近更新 更多