android項目 之 記事本(8) ----- 畫板功能之撤銷、恢複和清空

來源:互聯網
上載者:User

android項目 之 記事本(8) ----- 畫板功能之撤銷、恢複和清空

 

終於會做gif圖了,看下面的動態圖,是不是和QQ白板功能很像。

之前就簡單的只實現了在畫板上繪圖的功能,所以當時將自訂view直接寫在了activity中,這一節由於要實現撤銷、恢複及清空的功能,所以將分離出來,單獨寫成了一個java檔案PaintView.java,在該自訂view中實現畫板的基本操作。

因為將自訂view單獨分離出來,所以需要改到activity的布局檔案:如下

activity_paint.xml


其中com.example.notes.PaintView為自訂view

 

這節要實現的操作有撤銷,恢複,清空和儲存,下面分別討論三個操作的主要思想:

要實現撤銷與恢複,這裡有個前提,就是要將每次繪製的路徑存入棧中,這裡是存入List中。

1. 撤銷功能:

前提:將每次繪製的路徑存入List中,即存入savePath中

步驟:

1) 將畫布清空,這裡可以使用畫成的初始化操作
2) 將savePath中的最後一個路徑儲存到另一個List中,即deletePath(用於恢複),並且將此路徑從savePath中刪除

3) 取出savePath中的所有的路徑,重繪在畫布上面

 

2. 恢複功能:

前提:將每次撤銷的路徑存入List中,即存入deletePath中

步驟:

1) 取出deletePath中的最後一個路徑,並儲存到savePath中

2) 將取出的路徑重繪在畫布上

3) 從deletePath中刪除最後一個路徑

3.清空功能:

1) 直接清空畫布,調用畫布的初始化操作

2) 將兩個儲存路徑的List清空

 

4.儲存功能:

1) 獲得當前的時間,以時間作為繪圖檔案名(避免覆蓋)

2) 因為畫布是建立在Bitmap上的,所以將繪製好的BItMap儲存在SD卡上

3) 返回繪製檔案的路徑

 

以上操作並不難,重點是要將畫布上繪製的每個路徑儲存在List中,這裡需要注意,當按下時,應該重新建立路徑,抬起時,應該將按下時建立的路徑設定為null,只有這樣,才能儲存每個路徑。

下面直接給出自訂view的代碼,裡面也有注釋:

package com.example.notes;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.Iterator;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.View;/**** @category: View實現塗鴉、撤銷以及重做功能* @author: jesson20121020* @link: blog.csdn.net/jesson20121020* @date: 2014.9.19**/public class PaintView extends View  {private Canvas  mCanvas;private Path    mPath;private Paint   mBitmapPaint;private Bitmap  mBitmap;private Paint mPaint;    private ArrayList savePath;    private ArrayList deletePath;    private DrawPath dp;        private float mX, mY;        private static final float TOUCH_TOLERANCE = 4;                private int bitmapWidth;        private int bitmapHeight;                public PaintView(Context c) {            super(c);            //得到螢幕的解析度            DisplayMetrics dm = new DisplayMetrics();    ((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(dm);        bitmapWidth = dm.widthPixels;    bitmapHeight = dm.heightPixels - 2 * 45;                initCanvas();            savePath = new ArrayList();            deletePath = new ArrayList();                    }        public PaintView(Context c, AttributeSet attrs) {            super(c,attrs);            //得到螢幕的解析度            DisplayMetrics dm = new DisplayMetrics();    ((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(dm);                bitmapWidth = dm.widthPixels;    bitmapHeight = dm.heightPixels - 2 * 45;        initCanvas();            savePath = new ArrayList();            deletePath = new ArrayList();        }        //初始化畫布        public void initCanvas(){                mPaint = new Paint();            mPaint.setAntiAlias(true);            mPaint.setDither(true);            mPaint.setColor(0xFF00FF00);            mPaint.setStyle(Paint.Style.STROKE);            mPaint.setStrokeJoin(Paint.Join.ROUND);            mPaint.setStrokeCap(Paint.Cap.ROUND);            mPaint.setStrokeWidth(10);                          mBitmapPaint = new Paint(Paint.DITHER_FLAG);                                           //畫布大小             mBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight,                 Bitmap.Config.RGB_565);            mCanvas = new Canvas(mBitmap);  //所有mCanvas畫的東西都被儲存在了mBitmap中                        mCanvas.drawColor(Color.WHITE);            mPath = new Path();            mBitmapPaint = new Paint(Paint.DITHER_FLAG);                    }                        @Override        protected void onDraw(Canvas canvas) {                       canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);     //顯示舊的畫布                   if (mPath != null) {    // 即時的顯示    canvas.drawPath(mPath, mPaint);    }        }        //路徑對象         class DrawPath{        Path path;        Paint paint;        }                /**     * 撤銷的核心思想就是將畫布清空,     * 將儲存下來的Path路徑最後一個移除掉,     * 重新將路徑畫在畫布上面。     */        public void undo(){                System.out.println(savePath.size()+"--------------");        if(savePath != null && savePath.size() > 0){        //調用初始化畫布函數以清空畫布        initCanvas();                    //將路徑儲存列表中的最後一個元素刪除 ,並將其儲存在路徑刪除列表中            DrawPath drawPath = savePath.get(savePath.size() - 1);            deletePath.add(drawPath);            savePath.remove(savePath.size() - 1);                        //將路徑儲存列表中的路徑重繪在畫布上            Iterator iter = savePath.iterator();//重複儲存    while (iter.hasNext()) {    DrawPath dp = iter.next();    mCanvas.drawPath(dp.path, dp.paint);        }    invalidate();// 重新整理        }        }        /**     * 恢複的核心思想就是將撤銷的路徑儲存到另外一個列表裡面(棧),     * 然後從redo的列表裡面取出最頂端對象,     * 畫在畫布上面即可     */        public void redo(){        if(deletePath.size() > 0){        //將刪除的路徑列表中的最後一個,也就是最頂端路徑取出(棧),並加入路徑儲存列表中        DrawPath dp = deletePath.get(deletePath.size() - 1);        savePath.add(dp);        //將取出的路徑重繪在畫布上        mCanvas.drawPath(dp.path, dp.paint);        //將該路徑從刪除的路徑列表中去除        deletePath.remove(deletePath.size() - 1);        invalidate();        }        }        /*         * 清空的主要思想就是初始化畫布         * 將儲存路徑的兩個List清空         * */        public void removeAllPaint(){        //調用初始化畫布函數以清空畫布    initCanvas();    invalidate();//重新整理    savePath.clear();    deletePath.clear();        }               /*         * 儲存所繪圖形        * 返回繪圖檔案的儲存路徑        * */        public String saveBitmap(){      //獲得系統目前時間,並以該時間作為檔案名稱      SimpleDateFormat   formatter   =   new   SimpleDateFormat   ("yyyyMMddHHmmss");              Date   curDate   =   new   Date(System.currentTimeMillis());//擷取目前時間             String   str   =   formatter.format(curDate);              String paintPath = "";            str = str + "paint.png";            File dir = new File("/sdcard/notes/");            File file = new File("/sdcard/notes/",str);            if (!dir.exists()) {             dir.mkdir();             }             else{            if(file.exists()){            file.delete();            }            }                try {    FileOutputStream out = new FileOutputStream(file);    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);     out.flush();     out.close();     //儲存繪圖檔案路徑    paintPath = "/sdcard/notes/" + str;            } catch (FileNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();    } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();    }                 return paintPath;      }                        private void touch_start(float x, float y) {            mPath.reset();//清空path            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, y);                 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, mPaint);            savePath.add(dp);            mPath = null;                    }                @Override        public boolean onTouchEvent(MotionEvent event) {            float x = event.getX();            float y = event.getY();                        switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                                        mPath = new Path();                    dp = new DrawPath();                    dp.path = mPath;                    dp.paint = mPaint;                                        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;        }  }

 

接下來,就是在Activity中調用自訂的View中的這些操作方法:

private PaintView paintView;         private GridView paint_bottomMenu;
paint_bottomMenu = (GridView)findViewById(R.id.paintBottomMenu);paint_bottomMenu.setOnItemClickListener(new MenuClickEvent());paintView = (PaintView)findViewById(R.id.paint_layout);
          //設定功能表項目監聽器   class MenuClickEvent implements OnItemClickListener{  @Override  public void onItemClick(AdapterView parent, View view, int position,  long id) {  Intent intent;  switch(position){  //畫筆大小  case 0:    break;  //顏色  case 1:    break;  //撤銷  case 2:  paintView.undo();  break;  //恢複   case 3:  paintView.redo();  break;  //清空  case 4 :  paintView.removeAllPaint();  break;    default :  break;    }    }   }

這裡因為有儲存檔案,所以要有讀寫SD卡的許可權:


 

至此,已完成了畫板的撤銷,恢複,清空,儲存的功能,至於其他的功能,以後慢慢實現。


 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.