參考資料:
《Android開發(fā)藝術(shù)探索》
Layout過程##
Layout的作用是ViewGroup用來確定子元素的位置筹误,當(dāng)ViewGroup的位置被確定后伟骨,她在onLayout中會(huì)遍歷所有子元素,并調(diào)用其layout方法屿岂;
layout方法確定View本身的位置礼饱,而onLayout方法則會(huì)確定所有子元素的位置坏为;
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 設(shè)置View的4個(gè)頂點(diǎn)位置,初始化 mLeft 等4個(gè)值镊绪;
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<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;
}
layout方法大致流程如下:
- 通過setFrame來設(shè)置View的4個(gè)頂點(diǎn)的位置匀伏,即:mLeft,mTop蝴韭,mRight够颠,mBottom,用來確定View的位置榄鉴;
- 接著調(diào)用onLayout方法履磨,來確定子的位置;
Draw的過程##
draw的作用就是將View繪制到屏幕上;具體遵循:
- 繪制背景 background.draw(canvas);
- 繪制自己 onDraw;
- 繪制children(dispatchDraw);
- 繪制裝飾(onDrawScrollBars);
setWillNotDraw的說明####
如果一個(gè)View不需要繪制任何內(nèi)容牢硅,設(shè)置此標(biāo)志,系統(tǒng)會(huì)進(jìn)行相應(yīng)的優(yōu)化芝雪;
默認(rèn)情況下减余,View沒有啟動(dòng)這個(gè)優(yōu)化標(biāo)志;
默認(rèn)情況下惩系,ViewGroup啟用了這個(gè)標(biāo)志位岔;
當(dāng)自定義控件繼承自ViewGroup時(shí)并且本身不具備繪制功能時(shí),可開啟這個(gè)標(biāo)記位堡牡;
如果自定義的ViewGroup需要通過onDraw來繪制內(nèi)容時(shí)抒抬,就需要顯示關(guān)閉這個(gè)標(biāo)記位;
如在LinearLayout中:
setWillNotDraw(divider == null); // divider不為空是晤柄,ViewGroup的onDraw將會(huì)調(diào)用
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
return;
}
if (mOrientation == VERTICAL) {
drawDividersVertical(canvas);
} else {
drawDividersHorizontal(canvas);
}
}