一、为什么要自定义布局
Android系统内置的View无法实现我们的需求,需要针对所需要的业务需求定制需要的View。自定义View大部分只需要重写两个函数:onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw负责把当前这个View绘制出来。同时,还得写只少两个构造函数;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
1.1 onMeasure
自定义View,首先要测量宽高尺寸,在xml布局文件中的layout_width
和layout_height
参数可以不写具体尺寸,使用wrap_content
或者match_parent
。这两个设置没有指定具体大小,但是绘制在屏幕上的View必须有具体的宽高,所以必须自己去处理和设置尺寸。同时View类给了默认的处理,但如果View类的默认处理不满足需求,就得重写onMeasure函数。
onMeasure函数:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
参数中的widthMeasureSpec
和heightMeasureSpec
就是包含有宽和高的信息。它其中还包含测量模式,也就是一个int整数,里面包含测量莫斯和尺寸大小。
从int数据中提取测量模式和尺寸:
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
注意:这里的尺寸大小并不是最终View的尺寸大小,是父View提供的参考大小。
测量模式:
测量模式 | 表达意思 |
---|---|
UNSPECIFIED | 父容器没有对当前View有任何限制,当前View可以任意取尺寸 |
EXACTLY | 当前尺寸就是当前View应该取得尺寸 |
AT_MOST | 当前尺寸是当前View能取的最大尺寸 |
测量模式和布局的wrap_content
、match_parent
对应关系:
match_parent
→EXACTLY:match_parent
是利用父View提供的所有剩余空间,父View剩余空间是确定的,也就是测量模式的整数里面存放的尺寸。
wrap_content
→AT_MOST:将大小设置为包裹view内容,尺寸大小就是父View作为参考尺寸,只要不超过这个尺寸就可以,具体尺寸根据需求去设定。
固定尺寸(如100dp)
→EXACTLY:以指定大小为主。