
这篇文章本来想在一个月前就发布的,最近一直忙于国家电网手持终端的应用开发,所以没抽出时间来写。周末到了,终于可以闲下来整理整理。话不多说,直奔主题。
Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。
首先大致说说需求:这是一个追求时尚、张扬个性的时代,我们希望在签名的地方,签名的是自己手写出来的很有个性的艺术字,而非根据手势识别出来的标准字体。
设计思路如下,在画板上进行签名(其实就是绘制图片),完成后保存为图片。然后将图片按照一定的比率进行缩放并显示在指定的位置。
这里给出一个实例,实例只是一个简单的例子,如有需要可以进行必要的扩展。这里我们需要一个Listener、一个Dialog、一个Activity这个三个java类。两个layout XML文件。
Listener很简单,主要是对手写板对话框的一个监听。
Java代码
1.public interface DialogListener {
2.
3. public void refreshActivity(Object object);
4.
5.}
接着是画板的Dialog
Java代码
1.package cn.handwriting;
2.
3.import android.app.Dialog;
4.import android.content.Context;
5.import android.graphics.Bitmap;
6.import android.graphics.Bitmap.Config;
7.import android.graphics.Canvas;
8.import android.graphics.Color;
9.import android.graphics.Paint;
10.import android.graphics.Path;
11.import android.os.Bundle;
12.import android.view.MotionEvent;
13.import android.view.View;
14.import android.view.Window;
15.import android.view.WindowManager.LayoutParams;
16.import android.widget.Button;
17.import android.widget.FrameLayout;
18.
19.
20.public class WritePadDialog extends Dialog {
21.
22. Context context;
23. LayoutParams p ;
24. DialogListener dialogListener;
25.
26. public WritePadDialog(Context context,DialogListener dialogListener) {
27. super(context);
28. this.context = context;
29. this.dialogListener = dialogListener;
30. }
31.
32. static final int BACKGROUND_COLOR = Color.WHITE;
33.
34. static final int BRUSH_COLOR = Color.BLACK;
35.
36. PaintView mView;
37.
38. /** The index of the current color to use. */
39. int mColorIndex;
40.
41. @Override
42. protected void onCreate(Bundle savedInstanceState) {
43. super.onCreate(savedInstanceState);
44. requestWindowFeature(Window.FEATURE_NO_TITLE);
45. requestWindowFeature(Window.FEATURE_PROGRESS);
46. setContentView(R.layout.write_pad);
47.
48. p = getWindow().getAttributes(); //获取对话框当前的参数值
49. p.height = 320;//(int) (d.getHeight() * 0.4); //高度设置为屏幕的0.4
50. p.width = 480;//(int) (d.getWidth() * 0.6); //宽度设置为屏幕的0.6
51. getWindow().setAttributes(p); //设置生效
52.
53.
54. mView = new PaintView(context);
55. FrameLayout frameLayout = (FrameLayout) findViewById(R.id.tablet_view);
56. frameLayout.addView(mView);
57. mView.requestFocus();
58. Button btnClear = (Button) findViewById(R.id.tablet_clear);
59. btnClear.setOnClickListener(new View.OnClickListener() {
60.
61. @Override
62. public void onClick(View v) {
63. mView.clear();
. }
65. });
66.
67. Button btnOk = (Button) findViewById(R.id.tablet_ok);
68. btnOk.setOnClickListener(new View.OnClickListener() {
69.
70. @Override
71. public void onClick(View v) {
72. try {
73. dialogListener.refreshActivity(mView.getCachebBitmap());
74. WritePadDialog.this.dismiss();
75. } catch (Exception e) {
76. e.printStackTrace();
77. }
78. }
79. });
80.
81. Button btnCancel = (Button)findViewById(R.id.tablet_cancel);
82. btnCancel.setOnClickListener(new View.OnClickListener() {
83.
84. @Override
85. public void onClick(View v) {
86. cancel();
87. }
88. });
. }
90.
91.
92. /**
93. * This view implements the drawing canvas.
94. *
95. * It handles all of the input events and drawing functions.
96. */
97. class PaintView extends View {
98. private Paint paint;
99. private Canvas cacheCanvas;
100. private Bitmap cachebBitmap;
101. private Path path;
102.
103. public Bitmap getCachebBitmap() {
104. return cachebBitmap;
105. }
106.
107. public PaintView(Context context) {
108. super(context);
109. init();
110. }
111.
112. private void init(){
113. paint = new Paint();
114. paint.setAntiAlias(true);
115. paint.setStrokeWidth(3);
116. paint.setStyle(Paint.Style.STROKE);
117. paint.setColor(Color.BLACK);
118. path = new Path();
119. cachebBitmap = Bitmap.createBitmap(p.width, (int)(p.height*0.8), Config.ARGB_8888);
120. cacheCanvas = new Canvas(cachebBitmap);
121. cacheCanvas.drawColor(Color.WHITE);
122. }
123. public void clear() {
124. if (cacheCanvas != null) {
125.
126. paint.setColor(BACKGROUND_COLOR);
127. cacheCanvas.drawPaint(paint);
128. paint.setColor(Color.BLACK);
129. cacheCanvas.drawColor(Color.WHITE);
130. invalidate();
131. }
132. }
133.
134.
135.
136. @Override
137. protected void onDraw(Canvas canvas) {
138. // canvas.drawColor(BRUSH_COLOR);
139. canvas.drawBitmap(cachebBitmap, 0, 0, null);
140. canvas.drawPath(path, paint);
141. }
142.
143. @Override
144. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
145.
146. int curW = cachebBitmap != null ? cachebBitmap.getWidth() : 0;
147. int curH = cachebBitmap != null ? cachebBitmap.getHeight() : 0;
148. if (curW >= w && curH >= h) {
149. return;
150. }
151.
152. if (curW < w)
153. curW = w;
154. if (curH < h)
155. curH = h;
156.
157. Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888);
158. Canvas newCanvas = new Canvas();
159. newCanvas.setBitmap(newBitmap);
160. if (cachebBitmap != null) {
161. newCanvas.drawBitmap(cachebBitmap, 0, 0, null);
162. }
163. cachebBitmap = newBitmap;
1. cacheCanvas = newCanvas;
165. }
166.
167. private float cur_x, cur_y;
168.
169. @Override
170. public boolean onTouchEvent(MotionEvent event) {
171.
172. float x = event.getX();
173. float y = event.getY();
174.
175. switch (event.getAction()) {
176. case MotionEvent.ACTION_DOWN: {
177. cur_x = x;
178. cur_y = y;
179. path.moveTo(cur_x, cur_y);
180. break;
181. }
182.
183. case MotionEvent.ACTION_MOVE: {
184. path.quadTo(cur_x, cur_y, x, y);
185. cur_x = x;
186. cur_y = y;
187. break;
188. }
1.
190. case MotionEvent.ACTION_UP: {
191. cacheCanvas.drawPath(path, paint);
192. path.reset();
193. break;
194. }
195. }
196.
197. invalidate();
198.
199. return true;
200. }
201. }
202.
203.}
Activity是程序的入口,这个必不可少。
Java代码
1.package cn.handwriting;
2.
3.import java.io.ByteArrayOutputStream;
4.import java.io.File;
5.import java.io.FileOutputStream;
6.import java.io.IOException;
7.import android.app.Activity;
8.import android.graphics.Bitmap;
9.import android.os.Bundle;
10.import android.os.Environment;
11.import android.view.View;
12.import android.view.View.OnClickListener;
13.import android.widget.ImageView;
14.import android.widget.TextView;
15.
16.public class HandwritingActivity extends Activity {
17. /** Called when the activity is first created. */
18.
19. private Bitmap mSignBitmap;
20. private String signPath;
21. private ImageView ivSign;
22. private TextView tvSign;
23. @Override
24. public void onCreate(Bundle savedInstanceState) {
25. super.onCreate(savedInstanceState);
26. setContentView(R.layout.main);
27. setTitle("欢迎使用手写签名");
28. ivSign =(ImageView)findViewById(R.id.iv_sign);
29. tvSign = (TextView)findViewById(R.id.tv_sign);
30.
31. ivSign.setOnClickListener(signListener);
32. tvSign.setOnClickListener(signListener);
33. }
34.
35.
36. private OnClickListener signListener = new View.OnClickListener() {
37.
38. @Override
39. public void onClick(View v) {
40. WritePadDialog writeTabletDialog = new WritePadDialog(
41. HandwritingActivity.this, new DialogListener() {
42. @Override
43. public void refreshActivity(Object object) {
44.
45. mSignBitmap = (Bitmap) object;
46. signPath = createFile();
47. /*BitmapFactory.Options options = new BitmapFactory.Options();
48. options.inSampleSize = 15;
49. options.inTempStorage = new byte[5 * 1024];
50. Bitmap zoombm = BitmapFactory.decodeFile(signPath, options);*/
51. ivSign.setImageBitmap(mSignBitmap);
52. tvSign.setVisibility(View.GONE);
53. }
54. });
55. writeTabletDialog.show();
56. }
57. };
58.
59. /**
60. * 创建手写签名文件
61. *
62. * @return
63. */
. private String createFile() {
65. ByteArrayOutputStream baos = null;
66. String _path = null;
67. try {
68. String sign_dir = Environment.getExternalStorageDirectory() + File.separator;
69.
70. baos = new ByteArrayOutputStream();
71. mSignBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
72. byte[] photoBytes = baos.toByteArray();
73. if (photoBytes != null) {
74. new FileOutputStream(new File(_path)).write(photoBytes);
75. }
76.
77. } catch (IOException e) {
78. e.printStackTrace();
79. } finally {
80. try {
81. if (baos != null)
82. baos.close();
83. } catch (IOException e) {
84. e.printStackTrace();
85. }
86. }
87. return _path;
88. }
.}
对应的两个layout文件
main.xml
Xml代码
1.
2. 4. android:layout_height="fill_parent" 5. android:orientation="vertical" > 6. 7. 9. android:layout_marginTop="50dp" 10. android:layout_width="wrap_content" 11. android:layout_height="wrap_content" 12. android:layout_gravity="center" 13. /> 14. 15. 17. android:layout_marginTop="50dp" 18. android:layout_below="@id/iv_sign" 19. android:layout_width="wrap_content" 20. android:layout_height="wrap_content" 21. android:layout_gravity="center" 22. android:text="点此签名" 23. /> 24.
write_pad.xml
Xml代码
1. 3. android:layout_width="fill_parent" 4. android:layout_height="fill_parent" 5. android:orientation="vertical" > 6. 7. 9. android:layout_width="fill_parent" 10. android:layout_height="0dp" 11. android:layout_weight="1" 12. android:background="@color/white"> 13. 14. 15. 17. android:layout_height="wrap_content" 18. android:background="@android:drawable/bottom_bar" 19. android:paddingTop="4dp" > 20. 21. 42. 43.
这里还有个样式的设置,所以在values下添加了一个colors.xml文件。具体参见样例。
