Android View 绘制流程之二:layout布局
系列文章:
Android View 绘制流程之一:measure测量
Android View 绘制流程之二:layout布局
Android View 绘制流程之三:draw绘制
Android View 绘制流程之四:绘制流程触发机制
layout(int left,int top,int right,int bottom)方法是View测绘系统的第二步,布局过程,是在measure测量后调用,四个参数就是其在父view中的相对位置;如果是ViewGroup,还要根据自己的位置、布局属性来决定子view的相对位置,对子view进行layout过程,布局子view需要重写onLayout进行。
一.layout整体流程
先来一个整体的流程图。
首先,会调用setFrame方法设置并判断新的ltrb,返回值是ltrb是否改变了:如果有一个改变的,则要返回true,向view加入DRAWN标志,说明要重绘;计算新的宽高(right-left、bottom-top),如果宽高变化了,需要重新invalidate一下原有区域,并且调用onSizeChanged回调(View可以重写该方法进行拦截);最后更新ltrb的值。如果setFrame后发现改变了位置(返回true)或者view有LAYOUT_REQUIRED标志(需要重新布局),就调用onLayout方法,然后回调为view添加的OnLayoutChangeListener,最后取消这些标志位即可;
public void layout(int l, int t, int r, int b) {
...
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);//更新ltrb、看是否改变位置
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//位置改变了或者需要重新布局
onLayout(changed, l, t, r, b);//交由ViewGroup子类重写实现布局子view
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;//取消标志位
//调用listener
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
//取消标志位
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
}
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean changed = false;
if (mLeft != left || mRight !&