当前位置: 移动技术网 > 移动技术>移动开发>Android > Android UI设计系列之自定义DrawView组件实现数字签名效果(5)

Android UI设计系列之自定义DrawView组件实现数字签名效果(5)

2019年07月24日  | 移动技术网移动技术  | 我要评论
最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要

最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了view的绘图原理,把用户在屏幕上的手指移动轨迹显示在屏幕上,接着把在屏幕上显示的轨迹view转换成一张图片,最后把图片保存到本地或者上传到服务器...
还是老规矩,首先看一下工程目录吧:

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的使用吧,首先看一下布局文件:

<?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中的代码实现吧:

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>里边已测试,果然有效果,呵呵,当时高兴坏了,现在再高兴一下,(*^__^*) 嘻嘻...

好了,现在我们运行程序来看一下效果图吧:

绘制签名:

当点击了保存按钮后,进入图库看看吧:

好了,数字签名的讲解到这里了,谢谢大家的阅读。

源码下载:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网