基本概念
测量模式 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
绘制整个ViewGroup
postInvalidate
非UI
线程中请求重绘View
示例
CustomView
设置文本时请求重新布局和绘制
1 | public void setText(String text){ |
目标
- 自定义
View
常见流程 View
的绘制- 处理事件分发流程