内容简介:一直没有自己梳理一遍 View 体系的知识,以前写自定义 View 一涉及细节就全靠 Google。最近在 deepin 下搞了一份 AOSP 项目,准备从源码中再学习一遍自定义 View 的写法。在开始之前,先写了一个简单的自定义 View,用来复习自定义 View 的流程。TaggedSeekBar 在 SeekBar 的基础上加了一个显示进度值的标签,也可以当做 ProgressBar 使用,最终效果如下(压缩的比较惨,重在领会精神):TaggedSeekBar 直接继承自 View,虽然比较简陋,但
一直没有自己梳理一遍 View 体系的知识,以前写自定义 View 一涉及细节就全靠 Google。最近在 deepin 下搞了一份 AOSP 项目,准备从源码中再学习一遍自定义 View 的写法。在开始之前,先写了一个简单的自定义 View,用来复习自定义 View 的流程。
TaggedSeekBar 在 SeekBar 的基础上加了一个显示进度值的标签,也可以当做 ProgressBar 使用,最终效果如下(压缩的比较惨,重在领会精神):
知识点
TaggedSeekBar 直接继承自 View,虽然比较简陋,但确实包含了自定义 View 的大部分知识点。比如:
- View 的坐标体系
- Paint 基本属性
- Canvas 基本绘制函数
- onMeasure 测量自身
- onTouchEvent 处理用户交互
详情就不展开说了,有很多大佬都专门写过的。
流程
写自定义 View 时,最重要的第一步是「拆」。良好的拆解可以使 xml 中的参数更易理解,也可以简化 onDraw 中的绘制坐标计算过程。
我把 TaggedSeekBar 拆分成三部分:progress bar,thumb 和 tag(tag 分为箭头和本体),详情如图(看我充满灵魂的手绘):
拆分以满足需求为主,尽量保证良好的可扩展性。拆完之后就可以开始编码了
1. xml属性配置
当多个自定义 attr 的 name 冲突时,可以将 attr 的定义提取到外层,结构是这样的:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="progressWidth" format="dimension|reference"/> <declare-styleable name="TaggedSeekBar"> <attr name="progressWidth"/> </declare-styleable> <declare-styleable name="XXProgressBar"> <attr name="progressWidth"/> </declare-styleable> </resources> 复制代码
2. 读取属性,配置默认值
xml 配置参数的缺点是无法限制属性关联,每个属性都可能没写,所以获取属性的时候都需要填入默认值。
设置的默认值需要考虑到 View 元素相关性,尽量少用固定值,这样能尽可能降低上手难度。
3. 测量和定位
View 的 layout 方式符合我们的需求,不需要重写 onLayout。onMeasure 需要重写来支持 wrap_content
。进度条是水平方向的,所以 width 能多大就取多大,height 可以 wrap_content
,最小高度只要显示完整内容就好。
//当height的测量模式是 AT_MOST 时, //height = tagHeight+ThumbHeight+indicatorHeight height = paddingBottom + paddingTop + thumbRadius * 2 + thumbStrokeWidth * 2 + indicatorHeight + tagHeight).toInt() 复制代码
4. 分层绘制
onDraw
中后绘制的内容会覆盖在上面,这决定了坐标计算的顺序。TaggedSeekBar 中的绘制顺序是:进度条底色->进度条->thumb->tag
1.进度条底色(圆角矩形)
2.进度条(圆角矩形,覆盖在底色上)
3.Thumb(圆形)
4.tagIndicator(三角形)
绘制 api 不包含的图形可以用 Path,复用之前需要 reset。
5.tag(圆角矩形)
5. 响应 Touch 事件
事件的处理从响应 ACTION_DOWN
开始,拿到 event 的坐标之后首先要确定点击位置是否支持拖动。
如果不支持就当无事发生,支持的话就开始处理 ACTION_MOVE
并重绘自身。
关于 Listener 的配置还是以满足需求为主,这里只添加了两种:一是随拖动实时回调进度,二是松手后回调一次。
Tips
在编码和写博客期间遇到了一些小问题,顺便记录一下。
1. attrs.xml 里 name 冲突
之前没太注意,一般都是换个名字对付过去了。正确解法应该是这样的: 【代码】
2. 真机录制 gif
用模拟器运行代码的时候可以使用 LICEcap 直接录制 gif,在手机上运行就稍微复杂了点,adb 不支持录制 gif,可以采取录制视频再转为 gif 的方式。转换 工具 推荐 ffmpeg 命令,一行代码搞定:
- -i | 输入文件
- -vf scale=360:-1 |转换的同时缩放尺寸,宽高比为 360:-1,-1 表示保持比例自适应高度
刚接触 ffmpeg,感觉用处很多,研究之后单独写一下吧。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- [Vue 2.x Todo 教程练习参考答案] 标为完成练习参考答案
- [Vue 2.x Todo 教程练习参考答案] 添加todo练习参考答案
- [Vue 2.x Todo 教程练习参考答案] 入门仪式_Hello_Vue练习参考答案
- python二级练习(4)
- python二级练习(6)
- python二级练习(7)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。