Notepad (8) for android projects ----- withdrawal, restoration, and clearing of the canvas Function
Finally, I will make a gif image. Check whether the dynamic figure below is similar to the QQ whiteboard function.
Previously, only the drawing function on the canvas was implemented. Therefore, the custom view was directly written into the activity. This section aims to implement the function of revoking, restoring, and clearing, therefore, it is separated and written into a java file PaintView. java to implement the basic operations of the canvas in the Custom view.
Because the custom view is separated separately, you need to change it to the layout file of the activity:
Activity_paint.xml
Com. example. notes. PaintView is the custom view.
The operations to be implemented in this section include undo, restore, clear, and save. The following describes the main ideas of the three operations:
To implement revocation and recovery, we need to save the path drawn each time to the stack, and store it in the List.
1. Revocation:
Prerequisites:Save the path drawn each time to the List, that is, to the savePath.
Steps:
1) Clear the canvas. You can use the initialization operation drawn here.
2) Save the last path in savePath to another List, that is, deletePath (for restoration), and delete this path from savePath.
3) retrieve all the paths in the savePath and repaint them on the canvas.
2. Restoration:
Prerequisites:Store the Undo path to the List, that is, to deletePath.
Steps:
1) extract the last path in deletePath and save it to savePath.
2) repaint the retrieved path on the canvas.
3) Delete the last path from deletePath
3. Clear function:
1) Clear the canvas directly and call the canvas initialization operation.
2) Clear the List of the two storage paths
4. Save:
1) obtain the current time and use time as the drawing file name (avoid overwriting)
2) because the canvas is built on Bitmap, save the drawn BItMap on the SD card.
3) return the path of the drawing file.
The preceding operations are not difficult. The focus is to save each path drawn on the canvas to the List. Note that when you press the button, you should recreate the path and lift it up, you should set the path created when you press it to null. Only in this way can you save each path.
The code for the custom view is directly provided below, which also contains comments:
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 implements graffiti, undo, and redo functions * @ 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 ); // obtain the screen resolution DisplayMetrics dm = new DisplayMetrics (); (Activity) c ). getWindowManager (). getdefadisplay display (). 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); // obtain the screen resolution DisplayMetrics dm = new DisplayMetrics (); (Activity) c ). getWindowManager (). getdefadisplay display (). getMetrics (dm); bitmapWidth = dm. widthPixels; bitmapHeight = dm. heightPixels-2*45; initCanvas (); savePath = new ArrayList
(); DeletePath = new ArrayList
();} // Initialize the canvas 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); // canvas size mBitmap = Bitmap. createBitmap (bitmapWidth, bitmapHeight, Bitmap. C Onfig. RGB_565); mCanvas = new Canvas (mBitmap); // All mCanvas objects are saved in mBitmap. drawColor (Color. WHITE); mPath = new Path (); mBitmapPaint = new Paint (Paint. DITHER_FLAG) ;}@ Override protected void onDraw (Canvas canvas) {canvas. drawBitmap (mBitmap, 0, 0, mBitmapPaint); // display the old canvas if (mPath! = Null) {// display canvas in real time. drawPath (mPath, mPaint) ;}// Path object class DrawPath {path Path; Paint paint ;}/ *** the core idea of Undo is to clear the canvas, * remove the last saved Path from the canvas. * re-paint the Path on the canvas. */Public void undo () {System. out. println (savePath. size () + "--------------"); if (savePath! = Null & savePath. size ()> 0) {// call the initialization canvas function to clear the canvas initCanvas (); // Delete the last element in the path save list, and save it in the path deletion list DrawPath drawPath = savePath. get (savePath. size ()-1); deletePath. add (drawPath); savePath. remove (savePath. size ()-1); // repaint the path in the path save list on the canvas Iterator
Iter = savePath. iterator (); // repeat the while (iter. hasNext () {DrawPath dp = iter. next (); mCanvas. drawPath (dp. path, dp. paint);} invalidate (); // refresh}/*** the core idea of restoration is to save the withdrawn path to another list (stack ), * Then, retrieve the top object from the redo list, and draw * on the canvas. */public void redo () {if (deletePath. size ()> 0) {// extract the last path (stack) from the deleted path list, that is, the top path, and add it to the path save list. DrawPath dp = deletePath. get (deletePath. size ()-1); savePath. add (dp); // re-paint the retrieved path on the canvas. mCan Vas. drawPath (dp. path, dp. paint); // remove deletePath from the deleted path list. remove (deletePath. size ()-1); invalidate () ;}/ ** the main idea of clearing is to initialize the canvas * and clear the two lists in the saved path **/public void removeAllPaint () {// call the initialization canvas function to clear the canvas initCanvas (); invalidate (); // refresh the savePath. clear (); deletePath. clear () ;}/ ** Save the drawn image * return the storage path of the drawing file **/public String saveBitmap () {// obtain the current system time, and use this time as the file name SimpleDateFormat formatter = new SimpleDateForm At ("yyyyMMddHHmmss"); Date curDate = new Date (System. currentTimeMillis (); // obtain the current time 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 (); // Save the drawing file path 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 (); // clear 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); // the source code is like this I did not understand. Why? 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 (); // clear screen break; case MotionEvent. ACTION_MOVE: touch_move (x, y); invalidate (); break; case MotionEvent. ACTION_UP: touch_up (); invalidate (); break;} return true ;}}
Next, we will call these operation methods in the Custom View in the Activity:
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);
// Set the menu item listener class MenuClickEvent implements OnItemClickListener {@ Override public void onItemClick (AdapterView
Parent, View view, int position, long id) {Intent intent; switch (position) {// brush size case 0: break; // color case 1: break; // cancel case 2: paintView. undo (); break; // restore case 3: paintView. redo (); break; // clear case 4: paintView. removeAllPaint (); break; default: break ;}}}
You must have the permission to read and write the SD card because the file is saved:
So far, you have completed the UNDO, restore, clear, and save functions of the canvas. Other functions will be implemented later.