保存手写签名

简介: 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文件。

目录
相关文章
|
存储 安全 开发工具
oss加密存储
阿里云OSS为数据安全提供多种加密机制,包括服务器端的SSE-S3(AES-256透明加密)、SSE-C(用户管理密钥)和CSE-KMS(结合KMS进行密钥管理)。此外,OSS支持客户端加密SDK和HTTPS传输加密,确保数据在传输和存储时的安全。通过ACL、Bucket策略和访问密钥身份验证,实现权限控制与身份验证,全方位保障用户数据的安全性和隐私。用户可按需选择适合的加密方式。
964 2
|
SQL 数据库 数据库管理
PowerDesigner16:导入SQL脚本、显示中文注释
PowerDesigner16:导入SQL脚本、显示中文注释
PowerDesigner16:导入SQL脚本、显示中文注释
|
数据采集 存储 XML
Python爬虫:深入探索1688关键词接口获取之道
在数字化经济中,数据尤其在电商领域的价值日益凸显。1688作为中国领先的B2B平台,其关键词接口对商家至关重要。本文介绍如何通过Python爬虫技术,合法合规地获取1688关键词接口,助力商家洞察市场趋势,优化营销策略。
|
人工智能 边缘计算 云计算
2024.11|云计算行业的商业模式创新方法及实践
截至2024年,全球云计算行业迈入全新阶段,从IaaS到大规模AI模型平台,技术与商业模式不断创新。本文分析全球最新技术进展,探讨云计算商业模式创新策略与实践,解析云服务厂商如何通过技术革新实现价值最大化,推动企业数字化与智能化转型。重点讨论AI与云计算的深度融合、边缘计算与去中心化发展、平台化与生态系统建设,以及数据安全与绿色云计算等关键议题。
974 30
|
人工智能 自然语言处理 搜索推荐
ECCV 2024:一眼临摹:瞥一眼就能模仿笔迹的AI
 【10月更文挑战第10天】在人工智能领域,手写文本生成技术迎来新突破。最新研究提出“一眼临摹”AI技术,仅需一个手写样本文即可模仿任意书法风格。该技术核心为One-DM模型,结合扩散模型与风格增强模块,实现高效、多样且高质量的手写文本生成,广泛应用于数字签名、个性化信件及艺术创作等领域。
884 2
|
存储 人工智能 Go
探索Gin框架:Golang使用Gin完成文件上传
探索Gin框架:Golang使用Gin完成文件上传
|
机器学习/深度学习 边缘计算 安全
互联网安全的现状与防护策略
互联网安全问题已经成为了一个全球性的挑战,涉及到个人隐私、商业利益和国家安全。为了应对不断增加的威胁,我们需要采取多层次的安全策略,包括强化密码安全性、更新软件、多层次防御和数据加密。随着技术的不断发展,我们有望在未来看到更多创新的安全解决方案的出现,以应对不断变化的网络威胁。
1078 1
互联网安全的现状与防护策略
|
存储 小程序 前端开发
uniapp微信小程序不强制登陆的逻辑(模仿大厂登陆)
uniapp微信小程序不强制登陆的逻辑(模仿大厂登陆)
565 0
|
缓存 Linux 芯片
Cache(一):VIVT、VIPT、PIPT等概要
Cache(一):VIVT、VIPT、PIPT等概要
1281 0

热门文章

最新文章