视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Android手写签名开发心得
2025-10-02 18:41:42 责编:小OO
文档
Android手写签名开发心得

 这篇文章本来想在一个月前就发布的,最近一直忙于国家电网手持终端的应用开发,所以没抽出时间来写。周末到了,终于可以闲下来整理整理。话不多说,直奔主题。

 

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.3.    android:layout_width="fill_parent"  

4.    android:layout_height="fill_parent"  

5.    android:orientation="vertical" >  

6.  

7.    8.         android:id="@+id/iv_sign"  

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.     16.        android:id="@+id/tv_sign"  

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.2.    xmlns:greendroid="http://schemas.android.com/apk/res/com.cyrilmottier.android.gdcatalog"  

3.    android:layout_width="fill_parent"  

4.    android:layout_height="fill_parent"  

5.    android:orientation="vertical" >  

6.  

7.    8.        android:id="@+id/tablet_view"  

9.        android:layout_width="fill_parent"  

10.        android:layout_height="0dp"  

11.        android:layout_weight="1"   

12.        android:background="@color/white">  

13.      

14.  

15.    16.        android:layout_width="fill_parent"  

17.        android:layout_height="wrap_content"  

18.        android:background="@android:drawable/bottom_bar"  

19.        android:paddingTop="4dp" >  

20.  

21.        22.            android:id="@+id/tablet_ok"  

23.            android:layout_width="0dp"  

24.            android:layout_height="wrap_content"  

25.            android:layout_weight="1"  

26.            android:text="确定" />  

27.          

28.        29.            android:id="@+id/tablet_clear"  

30.            android:layout_width="0dp"  

31.            android:layout_height="wrap_content"  

32.            android:layout_weight="1"  

33.            android:text="清除" />  

34.  

35.        36.            android:id="@+id/tablet_cancel"  

37.            android:layout_width="0dp"  

38.            android:layout_height="wrap_content"  

39.            android:layout_weight="1"  

40.            android:text="取消" />  

41.      

42.  

43.  

这里还有个样式的设置,所以在values下添加了一个colors.xml文件。具体参见样例。下载本文

显示全文
专题