基本概念
ViewGroup
继承 View
,但是用来作为一个容器,装载各种 View
以及对它们做 UI
布局,比如高、宽、对齐方式等等,布局文件中凡是以 layout_
开头的属性,都是传递给 ViewGroup
来解析和使用的。ViewGroup
主要是计算子 View
的测量高宽并决定他们的位置。 重写 LayoutParams
可以自定义子 View
的特定参数,比如 weight
等。
框架和层级结构
View
和 ViewGroup
的绘制流程框架:
层级结构如下:
重要 API
- onMeasure
测量自己的高宽;测量所有子View
的高宽 - onLayout
抽象函数,必须重写。自定义子View
的排列规则
自定义 ViewGroup
步骤
自定义布局属性及 LayoutParams
同样在 res/values/attr.xml
文件中定义 ViewGroup
的属性及样式。
1 | <attr name="custom_orientation"> |
在布局文件使用时,示例如下:
1 | <com.***.view.CustomLayout |
获取自定义布局属性
在 ViewGroup
或者自定义 LayoutParams
的构造方法中获取自定义属性值。
1 | public CustomLayout(Context context, AttributeSet attrs, int defStyleAttr) { |
重写 LayoutParams
相关方法
自定义类 LayoutParams
继承 ViewGroup.LayoutParams
,并定义布局所需的几个变量。
1 | public static class LayoutParams extends ViewGroup.LayoutParams{ |
如果自定义了 LayoutParams
,必须重写下面四个方法,确保能做类型转换。
1 |
|
注意:如果没有重写这四个方法,会导致子 View
获取的 LayoutParams
转换为自定义时抛出异常:CustomLayout.LayoutParams lp = (CustomLayout.LayoutParams) childView.getLayoutParams();
转换失败异常 Log
打印如下:java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to com.***.view.CustomLayout$LayoutParams
重写 onMeasure
实现两个功能:
- 计算子
View
的测量高宽 - 计算自身测量高宽
1 |
|
重写 onLayout
计算子 View
的具体布局位置
1 |
|
自定义
ViewGroup
中,至少需要重写onMeasure
和onLayout
总结
onMeasure
主要计算wrap_content
模式下的测量高宽,包含自己和所有的子View
onLayout
主要计算子View
布局的具体位置onDraw
绘制自己,展现需要显示的内容
自定义 ViewGroup
主要计算自身和子 View
的测量高宽,以及子 View
布局的具体位置。
自定义 View
主要计算自身的测量高宽,以及绘制自己。
问题
在 Log
跟踪中发现 onLayout
和 onMeasure
会被调用执行两次
目标
- 自定义
ViewGroup
常见流程 - 必须重写
onLayout
及需要实现那些功能 - 是否处理事件分发流程