最近在做一个项目,有一个要求就是在手机客户端上记录用户的笔迹,然后发往服务端进行笔记认证。于是就写了一个简单的绘图板,记录用户的笔迹及笔记经过的坐标值。网络连接代码暂时还没加上去。
主来,即要运行的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>