1.Layout过程
1.1 View的layout
view的layout方法用来确定view本身的位置
public void layout(int l, int t, int r, int b) {
...
// 1.
setFrame(l,t,r,b)
// 2.
onLayout(changed,l,t,r,b)
}
- 先通过setFrame来设定4个顶点位置,view在父容器中位置就确定下来,4个参数是基于父容器的左、上、右、下距离
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean changed = false;
...
}
- 在layout内部调用onLayout, 用于父容器确定子元素位置(View#onLayout() 默认是空实现),如果特殊需求一般不需要覆写
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
1.2 ViewGroup的layout
确定所有子元素的位置
viewGroup的layout为final方法,不能覆写,其实现为View.layout
@Override
public final void layout(int l, int t, int r, int b) {
if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
if (mTransition != null) {
mTransition.layoutChange(this);
}
super.layout(l, t, r, b);
} else {
// record the fact that we noop'd it; request layout when transition finishes
mLayoutCalledWhileSuppressed = true;
}
}
- ViewGroup.onLayout() 为抽象方法,需要覆写
@Override
protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);
比如自定义FlowLayout,继承自ViewGroup,如下覆写onLayout(…)
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
Rect rect = (Rect) getChildAt(i).getTag();
child.layout(rect.left, rect.top, rect.right, rect.bottom);
}
}
2. 总结
- View与ViewGroup的layout实为一套流程,View#onLayout()默认是空实现,ViewGroup#onLayout()是抽象方法,需要用户自己实现,需要根据具体的布局来实现,可参考TextView, LinearLayout的实现。
- measure过程确定测量宽高,layout过程确定4定点位置即最终宽高,有何不同?
measure, getMeasureWidth
layout, getWidth = mRight - mLeft
二者时序不同,值是相等的, measure先,layout后;
若覆写View.layout ,修改4点的参数,则会导致二者不同