参考资料:
《Android开发艺术探索》
Layout过程##
Layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,她在onLayout中会遍历所有子元素,并调用其layout方法;
layout方法确定View本身的位置,而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;
}
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
// setFrame 设置View的4个顶点位置,初始化 mLeft 等4个值;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList listenersCopy =
(ArrayList)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;
}
layout方法大致流程如下:
- 通过setFrame来设置View的4个顶点的位置,即:mLeft,mTop,mRight,mBottom,用来确定View的位置;
- 接着调用onLayout方法,来确定子的位置;
Draw的过程##
draw的作用就是将View绘制到屏幕上;具体遵循:
- 绘制背景 background.draw(canvas);
- 绘制自己 onDraw;
- 绘制children(dispatchDraw);
- 绘制装饰(onDrawScrollBars);
setWillNotDraw的说明####
如果一个View不需要绘制任何内容,设置此标志,系统会进行相应的优化;
默认情况下,View没有启动这个优化标志;
默认情况下,ViewGroup启用了这个标志;
当自定义控件继承自ViewGroup时并且本身不具备绘制功能时,可开启这个标记位;
如果自定义的ViewGroup需要通过onDraw来绘制内容时,就需要显示关闭这个标记位;
如在LinearLayout中:
setWillNotDraw(divider == null); // divider不为空是,ViewGroup的onDraw将会调用
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
return;
}
if (mOrientation == VERTICAL) {
drawDividersVertical(canvas);
} else {
drawDividersHorizontal(canvas);
}
}