android画图并实现撤销功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zs704966613/article/details/54838910

因为在项目后期会用到android的画线画框功能,所以趁着过年在家琢磨了一下,本以为很简单的功能,却用掉了一整天的时间,先将其中的坑说一下:

1.在画线过程中,以down事件的点为起点

2.如果以up事件的点为终点,监听up事件,执行画线操作,那么在手指滑动期间,是不执行画线操作的,只有在手指抬起的瞬间,才会画线,这样画出来的线是不准确的,由于在滑动过程中没有画线,所以线的最终位置可能和我们想要的结果有些偏差

3.如果在move事件中画线,不多说,直接上图:
这里写图片描述

代码1.0:
public boolean onTouch(View v, MotionEvent event) {
paint.setColor(Color.BLUE);

            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startX = (int) event.getX();
                    startY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    endX = (int) event.getX();
                    endY = (int) event.getY();
                    //画线
                    Shape shape = new LineShape(startX,startY,endX,endY);
                    shape.draw(canvas,paint);
                    imageView.setImageBitmap(bitmap_view);
                    break;
                case MotionEvent.ACTION_UP:
                    endX = (int) event.getX();
                    endY = (int) event.getY();
                    Shape shape1 = new LineShape(startX,startY,endX,endY);
                    shape.draw(canvas,paint);
                    break;                    
        default:
                    break;
            }
            return true;
         }

由于在move事件中不断的执行画线方法,所以画出来的线有很多。

解决思路:在每次up事件中将画线的结果保存在list,move事件中将画布和背景还原,重新画list中保存的历史记录,再画出当前移动的位置,这样每次move时候,如果手指没有抬起,还在调整线的位置时,list是不会保存这条记录的,待线的位置调整好,手指抬起时,再将本次画的线存入list。

代码2.0:
/*
* 重置画布
*
* */
public void resetCanvas(){
imageView.setImageBitmap(bitmap_view);
canvas = new Canvas(bitmap_view);
}

/*
画出list中保存的操作
 */
public void drawFromList(Canvas canvas,Paint paint,List<Shape> list){
    for (Shape shape : list){
        shape.draw(canvas,paint);
    }
}

public boolean onTouch(View v, MotionEvent event) {
paint.setColor(Color.BLUE);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
startY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
endX = (int) event.getX();
endY = (int) event.getY();
//1.重置页面
resetCanvas();
//2.画出list中保存的操作
drawFromList(canvas,paint,shapeList);
//3.画出本次拖动状态的操作
Shape shape = new LineShape(startX,startY,endX,endY);
shape.draw(canvas,paint);
imageView.setImageBitmap(bitmap_view);
break;
case MotionEvent.ACTION_UP:
endX = (int) event.getX();
endY = (int) event.getY();
//1.重置画布
resetCanvas();
//2.将新的操作加入list
Shape shape1 = new LineShape(startX,startY,endX,endY);
shapeList.add(shape1);
//3.画出list中保存的操作
drawFromList(canvas,paint,shapeList);
break;
default:
break;
}

            return true;
        }

结果如图:
这里写图片描述

结果竟然还是这样!只好一步步的debug,发现下面方法中的bitmap_view,并没有还原,每次move时画了条线上去,重置画布和背景时,用的还是被画过之后的
bitmap_view,所以实际上并没有效果。

public void resetCanvas(){
imageView.setImageBitmap(bitmap_view);
canvas = new Canvas(bitmap_view);
}
解决思路:在初始化时,复制一份背景图bitmap_tmp,在重置画布和背景时,再把bitmap_tmp复制给bitmap_view,这样就可以了。但是在实际过程中,还遇到了深复制浅复制的问题,如果使用浅复制,那么结果还是和上图一模一样,必须使用深复制才行。

代码n.0:
初始化时先执行下面这句:
bitmap_tmp = bitmap_view.copy(Bitmap.Config.ARGB_8888,true);
/*
* 重置画布
*
* */
public void resetCanvas(){
bitmap_view = bitmap_tmp.copy(Bitmap.Config.ARGB_8888,true);
imageView.setImageBitmap(bitmap_view);
canvas = new Canvas(bitmap_view);
}
其它代码不变。
结果如图:
这里写图片描述
代码只贴了imageView的onTouch方法,如果要实现撤销功能的话,就从list中删掉最后一次操作即可,代码如下。

/*
*
* 撤销功能
*
* */
public void undo(){
if(shapeList != null && shapeList.size() > 0){
//删除最后一次操作
shapeList.remove(shapeList.size() - 1);
}
}

代码中使用了Shape来提高可扩展性,如果画多种形状,矩形圆形等,在此基础上稍作改动即可。

如有错误,欢迎指正,谢谢!

猜你喜欢

转载自blog.csdn.net/zs704966613/article/details/54838910