android畫圖並實現撤銷功能

因爲在項目後期會用到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來提高可擴展性,如果畫多種形狀,矩形圓形等,在此基礎上稍作改動即可。

如有錯誤,歡迎指正,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章