基本概念
测量模式 MeasureSpec
MeasureSpec 由两部分组成:
mode: 测量模式size: 测量的尺寸大小

其中模式有三种:
- UNSPECIFIED
ViewGroup没有做约束,想要多大就多大,一般用于系统内部,如ListView等。 - EXACTLY
默认模式,按照给定的值精确计算,具体高宽值和match_parent都是这种模式。 - AT_MOST
相当于wrap_content,根据自身的内容的高宽来计算。
View 根据 ViewGroup 传入的测量值和模式,对自己宽高进行确定,并完成绘制。 onMeasure 实现测量,然后在 onDraw 中完成对自己的绘制。
重要 API
- onMeasure
测量,决定高宽等,不是必须但大部分都会重写,重写主要需要针对wrap_content模式计算自身实际的高宽,通过调用setMeasuredDimension来设置。如果指定具体的高宽或者match_parent可以不用重写,父类默认是以这种方式来测量的。 - onDraw
绘制,即如何展现,必须重写
自定义 View 步骤
自定义属性和样式
在 res/values/ 下建立一个 attrs.xml , 在里面定义 View 的属性和声明整个样式。
1 | <declare-styleable name="CustomView"> |
其中,format 一共有如下几种类型:string, boolean, color, dimension, enum, flag, float, fraction, integer, reference。
在布局文件中需要引入这个自定义的属性,先加上这一句(老版本需要手动导入自定义 View 的包名):xmlns:app="http://schemas.android.com/apk/res-auto"。后续就可以通过 app:custom*** 来设置自定义的属性了,如下所示:
1 | <com.***.view.CustomView |
在构造方法中获得自定义属性的值
解析自定义属性时,注意 styleable 是通过 declare-styleable 中名称拼接来的。
1 | final Resources.Theme theme = context.getTheme(); |
重写 onMesure
不是必须的,但是大部分都会重写。如果没有重写,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果;当我们设置为 WRAP_CONTENT 或者 MATCH_PARENT 系统帮我们测量的结果就是 MATCH_PARENT 的长度。所以当设置了 WRAP_CONTENT 时,需要代码中进行测量,即重写 onMesure 方法。
1 |
|
重写 onDraw
主要是通过 Paint 和 Canvas 将需要表达的内容画出来。本例只是仿照 TextView 显示一段文本比较简单,所以只需要画出文本就行。
1 |
|
View.draw() 的流程
1 | public void draw(Canvas canvas) { |
重新布局和绘制
API
requestLayout
会调用onMeasure和onLayout进行重新测量及布局,但不会调用draw的过程,不会重新绘制任何View包括该调用者本身invalidate
只能在UI线程中执行。请求重绘View(也就是draw方法),哪个View请求invalidate系列方法,就重绘该View。即View只绘制该View,ViewGroup绘制整个ViewGrouppostInvalidate
非UI线程中请求重绘View
示例
CustomView 设置文本时请求重新布局和绘制
1 | public void setText(String text){ |
目标
- 自定义
View常见流程 View的绘制- 处理事件分发流程