最近在做一个项目,有一个要求就是在手机客户端上记录用户的笔迹,然后发往服务端进行笔记认证。于是就写了一个简单的绘图板,记录用户的笔迹及笔记经过的坐标值。网络连接代码暂时还没加上去。
主来,即要运行的Activity
1. package snowfox.android;
2.
3. import java.io.File;
4. import java.io.FileNotFoundException;
5. import java.io.FileOutputStream;
6. import java.io.IOException;
7. import java.io.PrintStream;
8.
9. import android.app.Activity;
10. import android.graphics.Bitmap;
11. import android.os.Bundle;
12. import android.view.View;
13. import android.view.View.OnClickListener;
14. import android.widget.Button;
15.
16. public class SimpleWrite extends Activity implements OnClickListener{
17. /** Called when the activity is first created. */
18. Button ok,cancer;
19. MyView mv;
20. Bitmap bitmap;
21.
22. @Override
23. public void onCreate(Bundle savedInstanceState) {
24. super.onCreate(savedInstanceState);
25. setContentView(R.layout.simple_write);
26. mv = (MyView)findViewById(R.id.MyView);
27. mv.setDrawingCacheEnabled(true);
28. ok = (Button)findViewById(R.id.buttonOk);
29. cancer = (Button)findViewById(R.id.buttonCancer);
30. ok.setOnClickListener(this);
31. cancer.setOnClickListener(this);
32. }
33.
34. public void onClick(View v) {
35. // TODO Auto-generated method stub
36. switch(v.getId())
37. {
38. case R.id.buttonOk:
39. {
40. /*
41. * 将Android的Bitmap对象保存成为一个文件,该类只有compress(Bitmap.CompressFormat format, int quality, OutputStream stream),
42. * 可以存为png和jpg,png可能还好说,但是jpg是有损压缩会降低图片的质量,其实Google还提供了一个API在Bitmap类,通过
43. * copyPixelsToBuffer(Buffer dst)这个方法来解决
44. */
45. //此处对图片质量要求不高,可以直接用前一种方法.
46. bitmap = mv.getDrawingCache(); //获得绘图板上的bitmap资源
47.
48. //新建文件以保存图片,文件名为系统当前时间
49. File imageFile = new File("/sdcard",System.currentTimeMillis() + ".png"); //若把文件保存到sdcard,须在配置文件中添加sd卡读写权限
50. try
51. {
52. FileOutputStream fos = new FileOutputStream(imageFile); //获取文件的输出流
53. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); //将bitmap的内容输出到文件输出流
54. fos.flush(); //刷新输出流,将输出流中数据输入文件
55. fos.close();
56. }
57. catch (FileNotFoundException e)
58. {
59. // TODO Auto-generated catch block
60. e.printStackTrace();
61. }
62. catch (IOException e)
63. {
64. // TODO Auto-generated catch block
65. e.printStackTrace();
66. }
67. mv.destroyDrawingCache(); //关掉缓冲区,以使相关无用的对象内存能被回收
68.
69. //以下为轨迹记录代码
70. int array[][][] = mv.cordinate;
71. //清空画板,并回收内存,在此处清空画板是因为上面已经把坐标信息记录下来了,因此之前画板的相关信息已不需要,可以清除
72. mv.initBiamap();
73. System.gc();
74. File cordinateFile = new File("/sdcard",System.currentTimeMillis() + ".txt");
75. try
76. {
77. PrintStream fps = new PrintStream(cordinateFile);
78.
79. for(int i = 0; i < 15; i++)
80. {
81. for(int j = 0; j < 30; j++)
82. {
83. fps.print(array[i][j][0]+" ");
84. fps.print(array[i][j][1]+" ");
85. fps.print("\t\t");
86. fps.flush();
87. }
88. fps.print("\r\n");
89. fps.flush();
90. }
91. fps.close();
92. }
93. catch (FileNotFoundException e) {
94. // TODO Auto-generated catch block
95. e.printStackTrace();
96. }
97. break;
98. }
99. case R.id.buttonCancer:
100. {
101. //此处将界面返回为初始状
102. mv.initBiamap(); //重新初始化mv组件,使其成为空白画板
103. System.gc();
104. break;
105. }
106. default:
107. break;
108. }
109. }
110. }
复制代码
定制组件:MyView:
1. package snowfox.android;
2.
3. import android.content.Context;
4. import android.graphics.Bitmap;
5. import android.graphics.Canvas;
6. import android.graphics.Color;
7. import android.graphics.CornerPathEffect;
8. import android.graphics.Paint;
9. import android.graphics.Path;
10. import android.graphics.PathEffect;
11. import android.util.AttributeSet;
12. import android.util.Log;
13. import android.view.GestureDetector;
14. import android.view.MotionEvent;
15. import android.view.View;
16. import android.view.GestureDetector.OnGestureListener;
17. import android.view.View.OnTouchListener;
18. import android.widget.Toast;
19.
20. public class MyView extends View implements OnTouchListener,OnGestureListener
21. {
22. int touchNum, pressNum; //笔画坐标数, 笔画数
23. int[][][] cordinate; //存储坐标的数组
24. public Paint paint;
25. public Path path;
26. private PathEffect effect;
27. Bitmap myBitmap;
28. GestureDetector testGestureDetector;
29. Canvas canvas;
30. public MyView(Context context, AttributeSet attrs)
31. {
32. super(context, attrs);
33. // TODO Auto-generated constructor stub
34. this.initBiamap();
35. this.setOnTouchListener(this);
36. this.setLongClickable(true); //只有设置了此项,才能监听手势
37. }
38. public void initBiamap()
39. {
40. touchNum = 0;
41. pressNum = 0;
42. cordinate = new int[20][100][2]; //最大笔画数20, 最大笔画坐标数100
43. canvas = new Canvas();
44. paint = new Paint();
45. path = new Path();
46. paint.setColor(Color.BLUE);
47. paint.setStyle(Paint.Style.STROKE);
48. paint.setStrokeWidth(3);
49. paint.setAntiAlias(true); //打开抗锯齿
50. effect = new CornerPathEffect(10); //打开圆角效果
51. testGestureDetector = new GestureDetector(this);
52. }
53. @Override
54. protected void onDraw(Canvas canvas)
55. {
56. super.onDraw(canvas);
57. paint.setAntiAlias(true);
58.
59. paint.setPathEffect(effect);
60. canvas.drawPath(path, paint);
61. invalidate(); //刷新组件,以显示当前效果
62. return;
63. }
64. public boolean onTouch(View v, MotionEvent event)
65. {
66.
67. // TODO Auto-generated method stub
68. //获取笔画坐标
69. float x= event.getX();
70. float y = event.getY();
71. Log.i("xy===========", x + " " + y+ "==================");
72. cordinate[pressNum][touchNum][0] = (int)x;
73. cordinate[pressNum][touchNum][1] = (int)y;
74.
75. if(touchNum == 0) //当touchNum = 0时,则为一个笔画的起点,因此将path起点移动到此点
76. path.moveTo(x,y);
77. else
78. path.lineTo(x,y);
79. touchNum++;
80. //Log.i("touchNum=====", touchNum + " ");
81. //Log.i("PressNum++++++++++++", pressNum + " ");
82. if(touchNum == 99) //笔画过长时,停止输入,并要求重新输入
83. {
84. Toast.makeText(this.getContext(), "笔画过于复杂,请重新输入", Toast.LENGTH_LONG).show();
85. this.initBiamap();
86. }
87. if(pressNum == 19) //笔画过多时,停止输入,并要求重新输入
88. {
89. Toast.makeText(this.getContext(), "笔画过于复杂,请重新输入", Toast.LENGTH_LONG).show();
90. this.initBiamap();
91. }
92. if((event.getAction()) == (MotionEvent.ACTION_UP)) //手指离开屏幕时,则下一笔为新笔画起点,因此相关数据置0
93. {
94. touchNum = 0;
95. pressNum ++;
96. }
97.
98. return testGestureDetector.onTouchEvent(event);
99. }
100. public boolean onDown(MotionEvent e) {
101. // TODO Auto-generated method stub
102. return false;
103. }
104. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY)
105. {
106. // TODO Auto-generated method stub
107. //n++;
108. //touchNum = 0;
109. //onDraw(canvas)
110. return false;
111. }
112. public void onLongPress(MotionEvent e) {
113. // TODO Auto-generated method stub
114.
115. }
116. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
117. float distanceY) {
118. // TODO Auto-generated method stub
119. return false;
120. }
121. public void onShowPress(MotionEvent e) {
122. // TODO Auto-generated method stub
123. }
124. public boolean onSingleTapUp(MotionEvent e) {
125. // TODO Auto-generated method stub
126. return false;
127. }
128. }
复制代码
布局文件:
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. android:background = "#c0c0c0"
7. >
8. <snowfox.android.MyView
9. android:layout_width = "wrap_content"
10. android:layout_height = "wrap_content"
11. android:id = "@+id/MyView"
12. android:layout_weight = "12"
13. android:background = "#ffffff"
14. />
15. <RelativeLayout
16. android:layout_width = "fill_parent"
17. android:layout_height = "wrap_content"
18. android:layout_gravity="bottom"
19. android:layout_weight = "1">
20. <Button
21. android:id = "@+id/buttonOk"
22. android:layout_width = "wrap_content"
23. android:layout_height = "wrap_content"
24. android:text = "确定"
25. android:layout_alignParentLeft = "true"
26. />
27. <Button
28. android:id = "@+id/buttonCancer"
29. android:layout_width = "wrap_content"
30. android:layout_height = "wrap_content"
31. android:text = "取消"
32. android:layout_alignParentRight = "true"
33. />
34. </RelativeLayout>
35. </LinearLayout>