Android简单涂鸦以及撤销、重做的实现方法
前段时间研究了下涂鸦功能的实现,其实单独的涂鸦实现起来还是挺简单的,关键的技术难点是撤销与重做功能的实现。但是这里暂时只说明下涂鸦功能的实现,高手勿喷哈,而且该功能在Android SDK提供的APIDemo当中就有的,但是如果能够将该地方的知识点搞懂的话,我认为View画图基本上是难不倒你了,特别是里面为什么要用一个中间的Bitmap。老规矩,还是先看看效果图吧:代码如下:
1.package cn.ych.tuya;
2.
3.import java.io.File;
4.import java.io.FileNotFoundException;
5.import java.io.FileOutputStream;
6.import java.io.IOException;
7.import java.util.ArrayList;
8.import java.util.Iterator;
9.import java.util.List;
10.
11.import android.content.Context;
12.import android.graphics.Bitmap;
13.import android.graphics.Canvas;
14.import android.graphics.Paint;
15.import android.graphics.Path;
16.import android.graphics.Bitmap.CompressFormat;
17.import android.os.Environment;
18.import android.view.MotionEvent;
19.import android.view.View;
20./**
21.*
22.* @category: View实现涂鸦、撤销以及重做功能
23.* @author: 锋翼
24.* @link: www.apkstory.com
25.* @date: 2012.1.4
26.*
27.*/
28.public class TuyaView extends View {
29.
30.private Bitmap mBitmap;
31.private Canvas mCanvas;
32.private Path mPath;
33.private Paint mBitmapPaint;// 画布的画笔
34.private Paint mPaint;// 真实的画笔
35.private float mX, mY;//临时点坐标
36.private static final float TOUCH_TOLERANCE = 4;
37.
38.private int screenWidth, screenHeight;// 屏幕長寬
39.
40.public TuyaView(Context context, int w, int h) {
41. super(context);
42. screenWidth = w;
43. screenHeight = h;
44.
45. mBitmap = Bitmap.createBitmap(screenWidth, screenHeight,
46. Bitmap.Config.ARGB_8888);
47. // 保存一次一次绘制出来的图形
48. mCanvas = new Canvas(mBitmap);
49.
50. mBitmapPaint = new Paint(Paint.DITHER_FLAG);
51. mPaint = new Paint();
52. mPaint.setAntiAlias(true);
53. mPaint.setStyle(Paint.Style.STROKE);
54. mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
55. mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
56. mPaint.setStrokeWidth(5);// 画笔宽度
57.
58.}
59.
60.@Override
61.public void onDraw(Canvas canvas) {
62. canvas.drawColor(0xFFAAAAAA);
63. // 将前面已经画过得显示出来
64. canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
65. if (mPath != null) {
66. // 实时的显示
67. canvas.drawPath(mPath, mPaint);
68. }
69.}
70.
71.private void touch_start(float x, float y) {
72. mPath.moveTo(x, y);
73. mX = x;
74. mY = y;
75.}
76.
77.private void touch_move(float x, float y) {
78. float dx = Math.abs(x - mX);
79. float dy = Math.abs(mY - y);
80.
81. 触摸间隔大于阈值才绘制路径
82. if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
83. // 从x1,y1到x2,y2画一条贝塞尔曲线,更平滑(直接用mPath.lineTo也是可以的)
84. mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
85. mX = x;
86. mY = y;
87. }
88.}
89.
90.private void touch_up() {
91. mPath.lineTo(mX, mY);
92. mCanvas.drawPath(mPath, mPaint);
93. }
94.
95.@Override
96.public boolean onTouchEvent(MotionEvent event) {
97. float x = event.getX();
98. float y = event.getY();
99.
100. switch (event.getAction()) {
101. case MotionEvent.ACTION_DOWN:
102. // 每次down下去重新new一个Path
103. mPath = new Path();
104.
105. touch_start(x, y);
106. invalidate();
107. break;
108. case MotionEvent.ACTION_MOVE:
109. touch_move(x, y);
110. invalidate();
111. break;
112. case MotionEvent.ACTION_UP:
113. touch_up();
114. invalidate();
115. break;
116. }
117. return true;
118.}
119.
120.}
上一讲当中,已经讲解了普通View实现涂鸦的功能,现在再来给涂鸦添加上撤销与重做的功能吧。撤销与重做在很多地方都是很重要的功能,比如PS里面、Word里面等等,而且大部分童鞋都能够想到要实现该功能应该需要用到堆栈,对于一些大牛的话可能就直接想到设计模式上面去了,比如命令模式就可以解决撤销与重做的问题。我们这里要讲解的是利用集合来完成该功能,其实也就是模拟栈,我相信你懂得。
老规矩,先上效果图:
代码如下:
1.package cn.ych.tuya;
2.
3.import java.io.File;
4.import java.io.FileNotFoundException;
5.import java.io.FileOutputStream;
6.import java.io.IOException;
7.import java.util.ArrayList;
8.import java.util.Iterator;
9.import java.util.List;
10.
11.import android.content.Context;
12.import android.graphics.Bitmap;
13.import android.graphics.Canvas;
14.import android.graphics.Paint;
15.import android.graphics.Path;
16.import android.graphics.Bitmap.CompressFormat;
17.import android.os.Environment;
18.import android.view.MotionEvent;
19.import android.view.View;
20./**
21.*
22.* @category: View实现涂鸦、撤销以及重做功能
23.* @author: 锋翼
24.* @link: www.apkstory.com
25.* @date: 2012.1.4
26.*
27.*/
28.public class TuyaView extends View {
29.
30.private Bitmap mBitmap;
31.private Canvas mCanvas;
32.private Path mPath;
33.private Paint mBitmapPaint;// 画布的画笔
34.private Paint mPaint;// 真实的画笔
35.private float mX, mY;// 临时点坐标
36.private static final float TOUCH_TOLERANCE = 4;
37.
38.// 保存Path路径的集合,用List集合来模拟栈
39.private static List<DrawPath> savePath;
40.// 记录Path路径的对象
41.private DrawPath dp;
42.
43.private int screenWidth, screenHeight;// 屏幕長寬
44.
45.private class DrawPath {
46. public Path path;// 路径
47. public Paint paint;// 画笔
48.}
49.
50.public TuyaView(Context context, int w, int h) {
51. super(context);
52. screenWidth = w;
53. screenHeight = h;
54.
55. mBitmap = Bitmap.createBitmap(screenWidth, screenHeight,
56. Bitmap.Config.ARGB_8888);
57. // 保存一次一次绘制出来的图形
58. mCanvas = new Canvas(mBitmap);
59.
60. mBitmapPaint = new Paint(Paint.DITHER_FLAG);
61. mPaint = new Paint();
62. mPaint.setAntiAlias(true);
63. mPaint.setStyle(Paint.Style.STROKE);
64. mPaint.setStrokeJoin(Paint.Join.ROUND);// 设置外边缘
65. mPaint.setStrokeCap(Paint.Cap.SQUARE);// 形状
66. mPaint.setStrokeWidth(5);// 画笔宽度
67.
68. savePath = new ArrayList<DrawPath>();
69.}
70.
71.@Override
72.public void onDraw(Canvas canvas) {
73. canvas.drawColor(0xFFAAAAAA);
74. // 将前面已经画过得显示出来
75. canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
76. if (mPath != null) {
77. // 实时的显示
78. canvas.drawPath(mPath, m
补充:移动开发 , Android ,