MeasureSpec 是一个 32 位的 int 类型,并且取了最前面的两位代表 Mode,后 30 位代表大小 Size。
3种模式
EXACTLY(精确模式,在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少,对应 MATCH_PARENT 和确定的值)
AT_MOST(WRAP_CONTENT,最大就是父控件的大小)
UNSPECIFIED(当前组件,可以随便用空间,不受限制,系统用,具体就体现在 NestedScrollView 和 ScrollView 中)
我们开发中,常用AT_MOST,EXACTLY
我们可能会给定默认大小,或者根据内容变化,经常都是固定大小
根视图
ViewRoot - performTraversals(执行遍历)
ViewGroup 还需要负责通知自己的子 View 进行绘制操作
private void performTraversals() {
...
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
...
//执行测量流程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
//执行布局流程
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
//执行绘制流程
performDraw();
}
onMeasure
每个 View 都有自己的大小,所以基本自定义 View 的时候都需要重写 onMeasure() 这个方法,以定制化我们的 View 的宽高
如果不重写这个方法,我们通常会出现 wrap_content 和 match_parent 是一样的显示效果
View 默认是会使用 getDefaultSize() 方法进行设置宽高的,在 AT_MOST和 EXACTLY 两种情况下都会直接使用测量规格里面的尺寸
在 ViewGroup 中,并没有去重写 View 的 onMeasure() 方法,而这都需要它的子类根据自己的逻辑去实现
ViewGroup 提供了一个 measureChildren() 方法来依次遍历每个子 View 对其进行测量。
在经过 onMeasure() 操作后,getMeasureWidth() 和 getMeasureHeight() 方法就可以拿到正确的返回值了
由于 View 的 measure 过程和 Activity 的生命周期方法不是同步执行的,如果 View 还没有测量完毕,那么获得的宽/高就是 0。所以在 onCreate()、onStart()、onResume() 中均无法正确得到某个 View 的宽高信息。可以通过在 onWindowFocusChanged() 判断获取到焦点后进行获取,或者使用 view.post()方式。
onLayout
onLayout() 方法主要作用是确定子 View 的显示位置,由于 View 已经是最小的层级,所以我们在自定义 View 的时候通常不需要管这个方法,而在自定义 ViewGroup 的时候就不得不注意这个方法
通过确认left,top,right,bottom四个值,确定了view的大小
获取view的大小,可以在onSizeChange之后
draw
drawBackground()
onDraw()
dispatchDraw()
onDrawScrollbars()
通常我的内容就是在draw中,代码编写也是主要在这里