Android UI设计系列之自定义DrawView组件实现数字签名效果(5)
最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了View的绘图原理,把用户在屏幕上的手指移动轨迹显示在屏幕上,接着把在屏幕上显示的轨迹View转换成一张图片,最后把图片保存到本地或者上传到服务器...
还是老规矩,首先看一下工程目录吧:
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 | public class DrawView extends View { /** * 签名画笔 */ private Paint paint; /** * 签名画布 */ private Canvas cacheCanvas; /** * 画笔路径 */ private Path path; /** * 缓存图片 */ private Bitmap cacheBitmap; /** * 图片宽度 */ private int width; /** * 图片高度 */ private int height; /** * 手指触摸屏幕时的X,Y坐标 */ private float xDown, yDown; /** * 是否正在绘制 */ private boolean isDrawing = false; /** * 默认画笔颜色 */ private int paintColor = Color.CYAN; /** * 默认画板背景色 */ private int canvasColor = Color.parseColor( "#bbccaa" ); public DrawView(Context context, int width, int height) { super(context); this.width = width; this.height = height; initWedgits(); } /** * 初始化组件 */ private void initWedgits() { try { paint = new Paint(Paint.DITHER_FLAG); // 设置抗锯齿 paint.setAntiAlias(true); // 设置画笔宽度 paint.setStrokeWidth(3); paint.setDither(true); // 设置样式 paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join. ROUND ); paint.setStrokeCap(Paint.Cap. ROUND ); // 画笔颜色 paint.setColor(paintColor); // 绘制路径 path = new Path(); // 创建空缓存图片 cacheBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); // 把画布内容画到空缓存图片上 cacheCanvas = new Canvas(cacheBitmap); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(canvasColor); canvas.drawBitmap(cacheBitmap, 0, 0, paint); canvas.drawPath(path, paint); } @Override public boolean onTouchEvent(MotionEvent event) { // 记录手指摁下屏幕时的X坐标 final float x = event.getX(); // 记录手指摁下屏幕时的Y坐标 final float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 手指摁下时清空之前的设置 path.reset(); // 设置路径起始点 path.moveTo(x, y); xDown = x; yDown = y; isDrawing = true; break ; case MotionEvent.ACTION_MOVE: // 移动下一点 path.quadTo(xDown, yDown, x, y); // 重新设置起点 xDown = x; yDown = y; isDrawing = true; break ; case MotionEvent.ACTION_UP: path.lineTo(xDown, yDown); // 手指抬起时绘制路径 cacheCanvas.drawPath(path, paint); // 路径重置 path.reset(); isDrawing = false; break ; default : break ; } // 刷新界面 invalidate(); return true; } /** * 设置画笔颜色 * * @param color * 画笔颜色 */ public void setPaintColor(int color) { paintColor = color; } /** * 设置画板颜色 * * @param color * 画板颜色 */ public void setCanvasColor(int color) { canvasColor = color; } /** * 返回绘画状态 * * @return【true:正在绘制】【false:绘制完成】 */ public boolean getDrawState() { return isDrawing; } /** * 返回Bitmap * * @return 返回绘制的图片 */ public Bitmap getBitmap() { return cacheBitmap; } } |
DrawView的代码注释都很清晰,我还是大致说下DrawView的执行逻辑吧,DrawView继承了View也就是说具有了View的所有功能,要实现图片绘制就要实现onDraw()方法,要实现对手指在屏幕上的轨迹绘制就需要获取轨迹坐标,所以需要重写onTouchEvent()放法,重点在onTouchEvent()方法中。当手指摁下时我们绘制起点,但是在绘制起点前需要先调用path.reset()方法,防止path进行二次重绘,path的moveTo方法就是来绘制当前触摸事件的起点,摁下完成之后调用inValidate()方法进行界面刷新。当手指移动时调用path.quadTo()方法,这个方法就是追加的意思,把新坐标点追加到path中,手指移动之后再调用inValidate()方法进行界面刷新,最后当手指抬起时,把在当前事件周期内的轨迹绘制到画板cacheCanvas上,最后再调用inValidate()方法进行界面刷新,因此一次的手指移动轨迹就绘制完成,当要进行下一次的绘制,就是重复以上操作了...
接下来我们看看DrawView的使用吧,首先看一下布局文件:
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 | <?xml version= "1.0" encoding= "utf-8" ?> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:orientation= "vertical" android:layout_width= "fill_parent" android:layout_height= "fill_parent" android:background= "#ffffff" > <TextView android:id= "@+id/title" android:layout_width= "fill_parent" android:layout_height= "wrap_content" android:text= "请绘制签名" android:textSize= "18sp" android:layout_margin= "5dip" android:gravity= "center" android:textColor= "#000000" /> <FrameLayout android:id= "@+id/contents" android:layout_width= "fill_parent" android:layout_height= "0dip" android:layout_weight= "1" android:layout_gravity= "center" android:background= "#aabbcc" > </FrameLayout> <Button android:layout_width= "match_parent" android:layout_height= "wrap_content" android:onClick= "save" android:text= "保存签名" /> </LinearLayout> |
乍一看布局文件中并没有使用我们自定义的DrawView,不过不用着急我是使用了通过在FrameLayout中动态添加的方法把DrawView添加进来的,好了,那紧接着看看MainActivity中的代码实现吧:
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 | public class MainActivity extends Activity { private FrameLayout frameLayout; private DrawView drawView; private TextView title; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initWedgits(); } /** * 初始化组件 */ private void initWedgits() { try { frameLayout = (FrameLayout) findViewById(R.id.contents); title = (TextView) findViewById(R.id.title); title.setText(Html.fromHtml( "<b>China中国<tt>中国</tt></b>China真伟大!" )); } catch (Exception e) { e.printStackTrace(); } } @Override public void onWindowFocusChanged(boolean hasFocus) { drawView = new DrawView(MainActivity.this, frameLayout.getWidth(), frameLayout.getHeight()); frameLayout.addView(drawView); } /** * 保存图片 * * @param view */ public void save(View view) { try { File file = new File(Environment.getExternalStorageDirectory() .getAbsolutePath() + "/handle.png" ); if (file.exists()) { file. delete (); } file.createNewFile(); if (drawView.getBitmap().compress(CompressFormat.PNG, 100, new FileOutputStream(file))) { Toast.makeText(getApplicationContext(), "图片保存成功" , 1000).show(); } } catch (Exception e) { e.printStackTrace(); } } } |
在MainActivity中的代码没什么好解释的,相信你一看就懂,最主要的是在save方法中使用了Bitmap的compress()方法,就是把图片存储在文件中,当我们签名结束之后点击保存签名按钮,签名图片就保存在了本地文件中了,当然了如果你想上传到后台服务器也不难,就是使用个异步操作进行图片上传就行了...
说明:当你运行程序的时候,会看见China中国中国真伟大!的字样,其中China和中国是加粗的效果,因为项目中有个需求让把汉字也加粗,上网上找了些方法,但是都是对英文和数字有效果对中文暂时没效果,我也是无意看源码中的注释,其中注释里边有加粗的文字说明,我就点击进去了,结果发现注释里的标签是<tt></tt>,当时脑子一转就想估计<tt>标签可以实现对汉字的加粗效果,呵呵,功夫不付有心人,把<tt>标签放到<b>里边已测试,果然有效果,呵呵,当时高兴坏了,现在再高兴一下,(*^__^*) 嘻嘻...
好了,现在我们运行程序来看一下效果图吧:
绘制签名:
当点击了保存按钮后,进入图库看看吧:
好了,数字签名的讲解到这里了,谢谢大家的阅读。
源码下载: Android UI实现数字签名效果
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持phpstudy。