Android自定义控件实现简单写字板功能
先来看看效果图
就是简单的根据手指写下的轨迹去画出内容
一、实现
之前一篇文章里提到了android官方给出的自定义控件需要考虑以下几点:
创建view
处理view的布局
绘制view
与用户进行交互
优化已定义的view
就按照这个步骤来完成今天的自定义控件
1、创建view
上篇提到创建view这一步的时候要考虑的就是很简单的自定义属性的声明、使用。
今天的控件可以有一些什么自定义属性呢?要实现写字板,其实就是三个东西:写字板的颜色、笔的颜色、笔的粗细。所以接下来自定义属性。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="writingboardview"> <attr name="boardbackground" format="color"></attr> <!--画板颜色--> <attr name="paintcolor" format="color"></attr> <!--画笔颜色--> <attr name="paintwidth" format="dimension"></attr> <!--画笔宽度--> </declare-styleable> </resources>
定义了就是为了要使用
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:custom="http://schemas.android.com/apk/res-auto" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" tools:context="com.qiangyu.test.writingboardview.mainactivity"> <com.qiangyu.test.writingboardview.view.writingboardview android:layout_width="match_parent" android:layout_height="match_parent" custom:paintcolor="@color/coloraccent" custom:boardbackground="@color/colorprimary" custom:paintwidth="3dp"/> </relativelayout>
简单的设置了boardbackground、paintwidth和paintcolor属性
使用这里只需要注意命名空间,android提供给我们的用android,我们可以自定义我们属性的命名空间
写法为:xmlns:你取的名=”http://schemas.android.com/apk/res-auto”,这里的res-auto可以换成你控件的包名
在xml布局文件中设置的属性要在自定义属性中获取到,所以我们必须实现带有context, attributeset的构造方法
private int mboardbackground;//画板颜色 private int mpaintcolor;//画笔颜色 private int mpaintwidth;//画笔宽度 private path mpath; private paint mpaint;//画笔 public writingboardview(context context) { this(context,null); } public writingboardview(context context, attributeset attrs) { this(context, attrs,0); } public writingboardview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context,attrs); } private void init(context context,attributeset attrs) { typedarray a = context.obtainstyledattributes(attrs,r.styleable.writingboardview); mboardbackground = a.getcolor(r.styleable.writingboardview_boardbackground,color.white); mpaintcolor = a.getcolor(r.styleable.writingboardview_paintcolor,color.blue); mpaintwidth = a.getdimensionpixelsize(r.styleable.writingboardview_paintwidth, (int) typedvalue.applydimension(typedvalue.complex_unit_dip,5,getresources().getdisplaymetrics())); a.recycle(); mpaint = new paint(); mpath = new path(); setbackgroundcolor(mboardbackground); mpaint.setcolor(mpaintcolor); mpaint.setstrokewidth(mpaintwidth); mpaint.setstyle(paint.style.stroke); mpaint.setantialias(true); }
上面代码确保了每个构造方法最终都调用了第三个构造方法里的init(context,attrs) 方法来获取自定义属性和初始化一些信息
通过固定的写法、简单的获取到自定义属性,并且给当前view设置背景、为paint设置了样式和颜色。完成写字板很重要的就是这里的path类。
先来介绍一下path类
看构造方法的注释
/** * the path class encapsulates compound (multiple contour) geometric paths * consisting of straight line segments, quadratic curves, and cubic curves. * it can be drawn with canvas.drawpath(path, paint), either filled or stroked * (based on the paint's style), or it can be used for clipping or to draw * text on a path. */ public class path { ... }
大体就是说path封装了由了直线和各种曲线组成几何图形信息。我们可以调用canvas通过drawpath方法来画一些东西。
我们最终的draw就是需要用到drawpath
path里包含了很多设置几何图形的方法如addrect、addarc。
今天重点说用到的两个方法:
/** * set the beginning of the next contour to the point (x,y). * * @param x the x-coordinate of the start of a new contour * @param y the y-coordinate of the start of a new contour */ public void moveto(float x, float y) { native_moveto(mnativepath, x, y); }
moveto方法就是设置下一个连线或者图形最开始的位置。
/** * add a line from the last point to the specified point (x,y). * if no moveto() call has been made for this contour, the first point is * automatically set to (0,0). * * @param x the x-coordinate of the end of a line * @param y the y-coordinate of the end of a line */ public void lineto(float x, float y) { issimplepath = false; native_lineto(mnativepath, x, y); }
lineto方法简单的添加一条上一个点到当前点的线。
有了这两个方法我们就可以实线写字板了
2、处理view的布局
由于这个自定义控件本身就需要一块内容当写字板,所以就不用特别的布局处理了,只是在mode为unspecified的时候可能会导致布局显示不出来。
在这里就不进行特殊处理了。
3、绘制view、与用户进行交互
由于该控件本身就需要交互才产生效果,所以之前的两步放在一起考虑了。
上面说到过canvas有一个drawpath方法。drawpath最后绘制出来什么样其实是看path里包含的信息。
我们要实现实时显示手写的内容,只需要在滑动的时候获取的坐标通过path的lineto方法将线一点一点的连起来。
当手指抬起再落下的时候应该又是一条新的线,所以在落下的时候我们需要调用moveto方法来为下一条轨迹设置一个起点。
@override public boolean ontouchevent(motionevent event) { float touchx = event.getx(); float touchy = event.gety(); switch (event.getaction()){ case motionevent.action_down: mpath.moveto(touchx,touchy);//重新设置即将出现的线的起点 break; case motionevent.action_move: mpath.lineto(touchx,touchy);//连线 break; case motionevent.action_up: break; } invalidate();//通知系统重绘 return true;//要处理当前事件 }
在ontouch中return true表示要处理当前事件。并且在每一次操作调用invalidate来绘制界面,我们的ondraw 方法只需要简单的调用drawpath就可以了
@override protected void ondraw(canvas canvas) { super.ondraw(canvas); canvas.drawpath(mpath,mpaint); }
总结
其实就是通过手指的触摸事件来控制轨迹的改变,按照固定的模式,一个简单的自定义控件就大功告成啦!
一个简单的写字板就基本完成了,当然你感兴趣可以扩展一下,加上在运行时改变画笔的颜色、画板的颜色。添加字体擦除去的功能。
上一篇: Java追加文件内容的三种方法实例代码
下一篇: mysqlsla慢查询分析工具使用笔记