登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 224|回复: 5

Android自定义控件实现简单写字板功能,android中自定义控件

[复制链接]

424

主题

798

帖子

1946

安币

手工艺人

发表于 2018-1-11 15:39:03 | 显示全部楼层 |阅读模式

        先来看看效果图

        

        就是简单的根据手指写下的轨迹去画出内容

        一、实现

        之前一篇文章里提到了android官方给出的自定义控件需要考虑以下几点:

        创建view

        处理view的布局

        绘制view

        与用户进行交互

        优化已定义的view

        就按照这个步骤来完成今天的自定义控件

        1、创建view
上篇提到创建view这一步的时候要考虑的就是很简单的自定义属性的声明、使用。

        今天的控件可以有一些什么自定义属性呢?要实现写字板,其实就是三个东西:写字板的颜色、笔的颜色、笔的粗细。所以接下来自定义属性。

[Java] 查看源文件 复制代码
<

        定义了就是为了要使用

[Java] 查看源文件 复制代码
<

        简单的设置了boardbackground、paintwidth和paintcolor属性

        使用这里只需要注意命名空间,android提供给我们的用android,我们可以自定义我们属性的命名空间
写法为:xmlns:你取的名=”http://schemas.android.com/apk/res-auto”,这里的res-auto可以换成你控件的包名

        在xml布局文件中设置的属性要在自定义属性中获取到,所以我们必须实现带有context, attributeset的构造方法

        

[Java] 查看源文件 复制代码
  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类

        看构造方法的注释

[Java] 查看源文件 复制代码
/**
 * 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。
今天重点说用到的两个方法:

[Java] 查看源文件 复制代码
 /**
   * 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方法就是设置下一个连线或者图形最开始的位置。

[Java] 查看源文件 复制代码
/**
   * 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方法来为下一条轨迹设置一个起点。

[Java] 查看源文件 复制代码
 @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就可以了

[Java] 查看源文件 复制代码
 @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);
    canvas.drawpath(mpath,mpaint);
  }

        总结

        其实就是通过手指的触摸事件来控制轨迹的改变,按照固定的模式,一个简单的自定义控件就大功告成啦!


17

主题

8993

帖子

2352

安币

Android大神

Rank: 6Rank: 6

发表于 2018-1-13 01:38:37 | 显示全部楼层
楼主是好人,回个帖会有安币吗?

21

主题

9221

帖子

2063

安币

Android大神

Rank: 6Rank: 6

发表于 2018-1-14 03:55:11 | 显示全部楼层
支持楼主,支持安卓巴士!

2

主题

9176

帖子

2494

安币

Android大神

Rank: 6Rank: 6

发表于 2018-1-14 20:53:04 | 显示全部楼层
感谢大神~

62

主题

9515

帖子

927

安币

代码手工艺人

学海无涯

Rank: 4

QQ达人

发表于 2018-1-15 08:26:46 | 显示全部楼层
感觉楼主很用心,辛苦啦~

8

主题

9028

帖子

3560

安币

码皇(巴士元老)

Rank: 8Rank: 8

发表于 2018-1-15 19:38:54 | 显示全部楼层
支持,感谢,祝巴士越来越好~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区
联系我们
关闭
合作电话:
15618560077
Email:
805941275@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表