本文詳細介紹view的繪制過程,view的繪制過程由measure、layout、draw 三部分組成。
measure : 測量view的寬和高。
layout : 确定view 四個點(top、left、 right、bottom)在父容器的最終位置。
draw : 将view繪制到螢幕上面。
view的繪制首先調用ViewRootImpl類的performTraversales方法,裡面決定要不要measure、layout、draw 。具體過程如下:
會先周遊ViewGroup的子View,其實最後就是調用View的Measure、Layout、Draw三個方法。
1:measure
測量過程主要與MeasureSpec和LayoutParams有關系,MeasureSpec是一個32位int型數,高2位代表SpecMode ,低30位 表示 SpecSize。
SpecMode有3種:UNSPECIFIED、EXACTLY、AT_MOST。
UNSPECIFIED:父容器不對View做任何的限制,要多大給多大。
EXACTLY:父容器已經檢測出View所需的大小,其值就是SpecSize。
AT_MOST:父容器指定了一個可用大小,View不能超過這個值。
LayoutParams有3個:FILL_PARENT、WRAP_CONTENT 、MATCH_PARENT。
子View的MeasureSpec的值由父容器的MeasureSpec和子View的 LayoutParams決定。
具體來說:如果子View的LayoutParams為MATCH_PARENT,父容器的SpecMode為AT_MOST,那麼子View也是AT_MOST,且其大小不會超過父容器的剩餘空間。
2:layout
public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != ) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
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);
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 = ; 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;
}
在view的layout函數中,首先會通過setFrame擷取到 mLeft、mTop、mBottom、mRight4個點的值,然後調用onLayout函數。
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
可以看出,在View的onLayout函數中并沒有具體的方法實作,onLayout跟具體的布局有關系,具體可以看LinearLayout的函數實作。
3:draw
Draw函數主要是将View繪制到螢幕上,可以從源碼上面看出主要包含以下幾步,這裡就不貼源碼了:
1:繪制背景
2:繪制自己
3:繪制children
4:繪制裝飾