保存手写签名

简介: Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。   首先大致说说需求:这是一个追求时尚、张扬个性的时代,我们希望在签名的地方,签名的是自己手写出来的很有个性的艺术字,而非根据手势识别出来的标准字体。   设计思路如下,在画板上进行签名(其实就是绘制图片),完成后保存

Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。

 

首先大致说说需求:这是一个追求时尚、张扬个性的时代,我们希望在签名的地方,签名的是自己手写出来的很有个性的艺术字,而非根据手势识别出来的标准字体。

 

设计思路如下,在画板上进行签名(其实就是绘制图片),完成后保存为图片。然后将图片按照一定的比率进行缩放并显示在指定的位置。

 

这里给出一个实例,实例只是一个简单的例子,如有需要可以进行必要的扩展。这里我们需要一个Listener、一个Dialog、一个Activity这个三个java类。两个layout XML文件。

 

Listener很简单,主要是对手写板对话框的一个监听。

1
2
3
4
5
public interface DialogListener {
      
     public void refreshActivity(Object object);
  
}

接着是画板的Dialog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package cn.handwriting;
  
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.FrameLayout;
  
  
public class WritePadDialog extends Dialog {
  
     Context context;
     LayoutParams p ;
     DialogListener dialogListener;
  
     public WritePadDialog(Context context,DialogListener dialogListener) {
         super (context);
         this .context = context;
         this .dialogListener = dialogListener;
     }
  
     static final int BACKGROUND_COLOR = Color.WHITE;
  
     static final int BRUSH_COLOR = Color.BLACK;
  
     PaintView mView;
  
     /** The index of the current color to use. */
     int mColorIndex;
  
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         requestWindowFeature(Window.FEATURE_PROGRESS);
         setContentView(R.layout.write_pad);
          
         p = getWindow().getAttributes();  //获取对话框当前的参数值  
         p.height = 320; //(int) (d.getHeight() * 0.4);   //高度设置为屏幕的0.4
         p.width = 480; //(int) (d.getWidth() * 0.6);    //宽度设置为屏幕的0.6          
         getWindow().setAttributes(p);     //设置生效
          
          
         mView = new PaintView(context);
         FrameLayout frameLayout = (FrameLayout) findViewById(R.id.tablet_view);
         frameLayout.addView(mView);
         mView.requestFocus();
         Button btnClear = (Button) findViewById(R.id.tablet_clear);
         btnClear.setOnClickListener( new View.OnClickListener() {
  
             @Override
             public void onClick(View v) {
                  mView.clear();
             }
         });
  
         Button btnOk = (Button) findViewById(R.id.tablet_ok);
         btnOk.setOnClickListener( new View.OnClickListener() {
  
             @Override
             public void onClick(View v) {
                 try {
                     dialogListener.refreshActivity(mView.getCachebBitmap());
                     WritePadDialog. this .dismiss();
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
         });
          
         Button btnCancel = (Button)findViewById(R.id.tablet_cancel);
         btnCancel.setOnClickListener( new View.OnClickListener() {
              
             @Override
             public void onClick(View v) {
                 cancel();
             }
         });
     }
      
  
     /**
      * This view implements the drawing canvas.
      *
      * It handles all of the input events and drawing functions.
      */
     class PaintView extends View {
         private Paint paint;
         private Canvas cacheCanvas;
         private Bitmap cachebBitmap;
         private Path path;
  
         public Bitmap getCachebBitmap() {
             return cachebBitmap;
         }
  
         public PaintView(Context context) {
             super (context);                
             init();        
         }
  
         private void init(){
             paint = new Paint();
             paint.setAntiAlias( true );
             paint.setStrokeWidth(3);
             paint.setStyle(Paint.Style.STROKE);
             paint.setColor(Color.BLACK);                   
             path = new Path();
             cachebBitmap = Bitmap.createBitmap(p.width, (int)(p.height*0.8), Config.ARGB_8888);        
             cacheCanvas = new Canvas(cachebBitmap);
             cacheCanvas.drawColor(Color.WHITE);
         }
         public void clear() {
             if (cacheCanvas != null ) {
                  
                 paint.setColor(BACKGROUND_COLOR);
                 cacheCanvas.drawPaint(paint);
                 paint.setColor(Color.BLACK);
                 cacheCanvas.drawColor(Color.WHITE);
                 invalidate();          
             }
         }
  
          
          
         @Override
         protected void onDraw(Canvas canvas) {
             // canvas.drawColor(BRUSH_COLOR);
             canvas.drawBitmap(cachebBitmap, 0, 0, null );
             canvas.drawPath(path, paint);
         }
  
         @Override
         protected void onSizeChanged(int w, int h, int oldw, int oldh) {
              
             int curW = cachebBitmap != null ? cachebBitmap.getWidth() : 0;
             int curH = cachebBitmap != null ? cachebBitmap.getHeight() : 0;
             if (curW >= w && curH >= h) {
                 return ;
             }
  
             if (curW < w)
                 curW = w;
             if (curH < h)
                 curH = h;
  
             Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888);
             Canvas newCanvas = new Canvas();
             newCanvas.setBitmap(newBitmap);
             if (cachebBitmap != null ) {
                 newCanvas.drawBitmap(cachebBitmap, 0, 0, null );
             }
             cachebBitmap = newBitmap;
             cacheCanvas = newCanvas;
         }
  
         private float cur_x, cur_y;
  
         @Override
         public boolean onTouchEvent(MotionEvent event) {
              
             float x = event.getX();
             float y = event.getY();
  
             switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN: {
                 cur_x = x;
                 cur_y = y;
                 path.moveTo(cur_x, cur_y);
                 break ;
             }
  
             case MotionEvent.ACTION_MOVE: {
                 path.quadTo(cur_x, cur_y, x, y);
                 cur_x = x;
                 cur_y = y;
                 break ;
             }
  
             case MotionEvent.ACTION_UP: {
                 cacheCanvas.drawPath(path, paint);
                 path.reset();
                 break ;
             }
             }
  
             invalidate();
  
             return true ;
         }
     }
  
}

Activity是程序的入口,这个必不可少。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package cn.handwriting;
  
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
  
public class HandwritingActivity extends Activity {
     /** Called when the activity is first created. */
      
     private Bitmap mSignBitmap;
     private String signPath;
     private ImageView ivSign;
     private TextView tvSign;
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         setTitle( "欢迎使用手写签名" );
         ivSign =(ImageView)findViewById(R.id.iv_sign);
         tvSign = (TextView)findViewById(R.id.tv_sign);     
          
         ivSign.setOnClickListener(signListener);
         tvSign.setOnClickListener(signListener);
     }
      
      
     private OnClickListener signListener = new View.OnClickListener() {
          
         @Override
         public void onClick(View v) {
             WritePadDialog writeTabletDialog = new WritePadDialog(
                     HandwritingActivity. this , new DialogListener() {
                         @Override
                         public void refreshActivity(Object object) {                           
                              
                             mSignBitmap = (Bitmap) object;
                             signPath = createFile();
                             /*BitmapFactory.Options options = new BitmapFactory.Options();
                             options.inSampleSize = 15;
                             options.inTempStorage = new byte[5 * 1024];
                             Bitmap zoombm = BitmapFactory.decodeFile(signPath, options);*/                                                     
                             ivSign.setImageBitmap(mSignBitmap);
                             tvSign.setVisibility(View.GONE);
                         }
                     });
             writeTabletDialog.show();
         }
     };
      
     /**
      * 创建手写签名文件
      *
      * @return
      */
     private String createFile() {
         ByteArrayOutputStream baos = null ;
         String _path = null ;
         try {
             String sign_dir = Environment.getExternalStorageDirectory() + File.separator;          
             _path = sign_dir + System.currentTimeMillis() + ".jpg" ;
             baos = new ByteArrayOutputStream();
             mSignBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
             byte[] photoBytes = baos.toByteArray();
             if (photoBytes != null ) {
                 new FileOutputStream( new File(_path)).write(photoBytes);
             }
  
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try {
                 if (baos != null )
                     baos.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         return _path;
     }
}

对应的两个layout文件

main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical" >
  
     <ImageView
          android:id= "@+id/iv_sign"
          android:layout_marginTop= "50dp"
          android:layout_width= "wrap_content"
          android:layout_height= "wrap_content"
          android:layout_gravity= "center"
          />
      
      <TextView
         android:id= "@+id/tv_sign"
         android:layout_marginTop= "50dp"
         android:layout_below= "@id/iv_sign"
         android:layout_width= "wrap_content"
         android:layout_height= "wrap_content"
         android:layout_gravity= "center"
         android:text= "点此签名"
         />     
</LinearLayout>

write_pad.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical" >
  
     <FrameLayout
         android:id= "@+id/tablet_view"
         android:layout_width= "fill_parent"
         android:layout_height= "0dp"
         android:layout_weight= "1"
         android:background= "@color/white" >
     </FrameLayout>
  
     <LinearLayout
         android:layout_width= "fill_parent"
         android:layout_height= "wrap_content"
         android:background= "@android:drawable/bottom_bar"
         android:paddingTop= "4dp" >
  
         <Button
             android:id= "@+id/tablet_ok"
             android:layout_width= "0dp"
             android:layout_height= "wrap_content"
             android:layout_weight= "1"
             android:text= "确定" />
          
         <Button
             android:id= "@+id/tablet_clear"
             android:layout_width= "0dp"
             android:layout_height= "wrap_content"
             android:layout_weight= "1"
             android:text= "清除" />
  
         <Button
             android:id= "@+id/tablet_cancel"
             android:layout_width= "0dp"
             android:layout_height= "wrap_content"
             android:layout_weight= "1"
             android:text= "取消" />
     </LinearLayout>
  
</LinearLayout>

这里还有个样式的设置,所以在values下添加了一个colors.xml文件。

目录
相关文章
|
2月前
|
JSON 小程序 数据安全/隐私保护
小程序动态调试-解密加密数据与签名校验
本文主要讲解微信小程序加密、验签的情况下如何进行动态调试已获取签名以及加密信息
|
3月前
|
开发者 Python
使用 TypeVar 创建 Self 类型变量,方便用户在 Pycharm 编辑器中链式调用校验方法
使用 TypeVar 创建 Self 类型变量,方便用户在 Pycharm 编辑器中链式调用校验方法
30 0
|
6月前
|
缓存 JavaScript 安全
JS逆向 -- 分析某站b_lsid值加密过程
JS逆向 -- 分析某站b_lsid值加密过程
43 0
|
7月前
|
小程序
uniapp小程序实现横屏手写签名(整理)
uniapp小程序实现横屏手写签名(整理)
|
8月前
|
存储 前端开发 小程序
小程序封装手写签名组件
本文详细介绍了如何封装一个小程序手写签名组件,包括签名、保存签名、清除签名和撤销功能。我们使用了 canvas 来实现手写签名功能,通过自定义组件的方式来封装手写签名组件,使其可以在不同的页面中重复使用。同时,我们使用了面向对象的编程方式,将手写签名的逻辑封装在一个signaImage类中,使代码更加清晰易懂。最后希望能帮助大家更好地理解和使用本文介绍的手写签名组件。
342 0
|
8月前
|
编解码 前端开发
用canvas实现手写签名功能
用canvas实现手写签名功能
50 0
|
8月前
|
JSON 算法 前端开发
关于前端动态调试解密签名校验的分享
现在很多项目都进行了签名校验或者是使用例如RSA的方式对传输流量进行加密,那么我们可以通过本地的动态调试获取程序的加密逻辑、加密方法,从而绕过系统的防护对系统进行测试
|
10月前
|
算法
Qt实现一个重复文件检测小工具(原理:通过md5校验)
Qt实现一个重复文件检测小工具(原理:通过md5校验)
232 0
|
测试技术 数据格式
实用PostMan测试进阶操作 token校验 参数传递 存为环境变量 避免重复copy
实用PostMan测试进阶操作 token校验 参数传递 存为环境变量 避免重复copy
149 0
实用PostMan测试进阶操作 token校验 参数传递 存为环境变量 避免重复copy

热门文章

最新文章