这个题是某公司试题,挺有新意,正好记录下自定义View的用法。题目如下:
效果图gif中还有左右滑动的动态改变功能。
分析过程
分析一下题目,明显是要用到自定义View了,还有要求使用系统接口完成,所以不能出现第三方控件来绘图;可配置要求引用控件的时候有相关参数的引用设置;可复用,要求可作为三方库使用或module依赖。
分析到预览图的结构,绘制的大概有:
- 位置Text区域
- 倒三角指示
- 两种刻度标绘制以及长标数值绘制
- 最后还有上边提到的左右滑动动态显示数值,自定义监听接口获取到数值
实现思路
自定义View的三种方式有:组合系统控件、扩展系统控件、以及完全自定义控件
这个刻度尺,我们可以完全自定义,当然是最根本的解决方案,另一种就是可以用部分自定义+组合系统控件的方式完成、或者三种方式都用上。
1. 自定义黄色刻度尺+自定义绘制文字
2. 自定义黄色刻度尺+扩展TextView绘制文字
实现过程
实现上其实都要自定义绘制刻度尺,因为API中没有和他相似的控件来扩展,还有题目要求系统接口实现,所以这个部分是必须要自定义绘制的。所以这里选择完全自定义绘制吧:
- 继承View控件覆写onDraw()
- onTouchEvement()事件捕捉–滑动监听
- 位置计算,监听回调
实现上:
- onMeasure():View测量,模式有EXACTLY、AT_MOST、UNSPECIFIED三种,自定义控件不覆写此方法,系统默认为EXACTLY模式,不可使用自适应的wrap_content模式(不自己实现为match_parent实现效果),所以为了更好的体验,一般情况下要处理这个问题实现wrap_content的大小。
- onSizeChanged():组件大小改变时调用,比如横竖屏切换时
- onFinishInflate():从XML布局加载组建后调用
- onLayout():设置布局显示的位置,自定义ViewGroup的时候要设置子View位置,所以自定义view这里我们用不到了
- onTouchEvent():触摸事件处理
- onDraw():绘制视图,一般调用invalidate()或者postInvalidate()方法通知重绘
以上是常用到的重要方法,实现上也需要按需来覆写,这个例子,我们宽就match_parent,高就测量一下,所以要覆写onMeasure()、视图尺寸改变简洁来说就先不处理了。绘制必须要覆写到onDraw()方法了。只是自定义view所以用不到onLayout()方法。
实现代码:
Values文件夹下新建attrs.xml,定义我们的自定义view的内容样式,其中属性相应的是自定义的样式内容
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RulerView">
<attr name="back_color" format="color"/>
<attr name="scale_margin" format="integer"/>
<attr name="scale_count" format="integer"/>
<attr name="unit" format="string"/>
<attr name="value_max" format="integer"/>
<attr name="value_min" format="integer"/>
</declare-styleable>
</resources>
values文件夹下的colors.xml文件下添加黄色背景色:
colors.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="yellow">#FBDE00</color>
<color name="withe">#ffffff</color>
</resources>
最后是java文件下的自定义view类:
RulerView.java
public class RulerView extends View {
private int background;//背景颜色
private Paint paintBackground,paintLine,paintText,paintUnit,paintUnitText;//各个画笔
private int scale_margin;//刻度间距
private int scale_count;//每个大刻度间小刻度数目
private int ma