View的Layout过程,也就是布局子元素的过程,ViewGroup通过这个过程来确定子元素的位置,当ViewGroup的位置被确定了以后,就会在onLayout中遍历所有的子元素并且调用这些元素的layout方法,在layout方法中onLayout方法会被回调.下面我们从View的Layout方法开始看:
public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
//首先,在layout的时候,我们已经拿到了View的位置了,然后,我们记录下之前的View的位置信息。
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
//isLayoutModeOptical返回为true需要mParent为ViewGroup派生类的对象,
//并且mParent的isLayoutModeOptical也需要是true,一般来说,只要layoutMode不是LAYOUT_MODE_OPTICAL_BOUNDS
//那么,什么叫LAYOUT_MODE_OPTICAL_BOUNDS ?一般我们绘制了View的阴影、发光区域什么的,这种情况下,我们会有个区域影响到别的控件
//下面主要讲setFrame ,setFrame的最终结果就是重新设置View的位置,并且返回是否改变了View的位置。
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//执行onLayout的方法,当然,也是遍历子View,每个都要告诉ViewGroup
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
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;
}