写在开头:
随着工作的深入,越来越觉得的Android的基础知识不稳固。于是决定在空闲时间中补一下基础知识,顺便做个基础知识系列的笔记。
基本概念
ViewGroup的绘制流程
onMeasure(): 测量自己的大小,为正式布局提供建议。(注意,只是建议,至于用不用,要看onLayout)
onLayout():使用layout()函数对所有子控件布局;
onDraw():根据布局的位置绘图;
onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
其中 widthMeasureSpec 和 heightMeasureSpec分别有mode和size组成
mode
- UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;
- EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;对应 match_parent 或者具体值
- AT_MOST(至多),子元素至多达到指定大小的值。对应 wrap_content
获取方式
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
设定方式
setMeasuredDimension()
onLayout()
onLayout是实现所有子空间布局的函数。
实现逻辑,实际就是for循环对每一个child进行布局
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int top = 0;
int count = getChildCount();
for (int i=0;i<count;i++) {
View child = getChildAt(i);
int childHeight = child.getMeasuredHeight();
int childWidth = child.getMeasuredWidth();
child.layout(0, top, childWidth, top + childHeight);
top += childHeight;
}
}
常见疑问
getMeasuredWidth()与getWidth()的区别
- 首先getMeasureWidth()方法在measure()过程结束后就可以获取到了,而getWidth()方法要在layout()过程结束后才能获取到。
- getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,而getWidth()方法中的值则是通过layout(left,top,right,bottom)方法设置的。
onLayout()方法中可以获取setMeasuredDimension()设置的宽高,当最后用不用由onLayout()自己决定。所以getWidth()实际是有onLayout()中设置。
getMeasureWidth()是建议值。
getWidth() 是实际值。
视图自己什么时候被布局
同样是有父布局在onLayout()方法中布局的,只不过追溯到最根本的父布局为ViewRoot.
在ViewRoot中会首先调用自己的一个方法 setFrame()来设置自己的位置,然后调用onLayout()一层层的布局下去。