View繪制流程_第1頁
View繪制流程_第2頁
View繪制流程_第3頁
View繪制流程_第4頁
View繪制流程_第5頁
已閱讀5頁,還剩17頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、 public final void measure(i nt widthMeasureSpec, int heightMeasureSpec) / 回調(diào) onMeasure(方法 onM easure(widthMeasureSpec, heightMeasureSpec); 這個方法的兩個參數(shù)都是父View傳遞過來的,代表了父view的規(guī)格。他由兩部分組成, 咼2位表示 MODE,低30位表示size。 /View的onMeasure默認(rèn)實現(xiàn)方法 protected void onM easure(i nt widthMeasureSpec, 精品 int heightMeasureSpe

2、c) setMeasuredDimension( getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec) ); 對于非ViewGroup的View而言,通過調(diào)用上面默認(rèn)的 on Measure即可完成View的測量。 setMeasuredDime nsio n函數(shù) 是一個很關(guān)鍵的函數(shù),它完成了對 View的成員變量 mMeasuredWidth 和 mMeasuredHeight變量賦值。 publi

3、c static int getDefaultSize(i nt size, int measureSpec) int result = size; /通過MeasureSpe解析獲取 mode與size int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: res

4、ult = specSize; case MeasureSpec.EXACTLY: 精品 break; return result; protected int getSuggestedMinimumWidth() return (mBackground = null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth(); protected int getSuggestedMinimumHeight() return (mBackground = null) ? mMinHeight : max(mMinHeight, mBa

5、ckground.getMinimumHeight(); 在 ViewGroup 中定義了 measureChildren, measureChild, measureChildWith- measureChild。 Margi ns方法來對子視圖進(jìn)行測量,measureChildre n內(nèi)部實質(zhì)只是循環(huán)調(diào)用 protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) / 獲取子

6、視圖的 LayoutParams final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); / 調(diào)整 MeasureSpec /通過這兩個參數(shù)以及子視圖本身LayoutParams來共同決定子視圖的測量規(guī)格 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUs

7、ed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); /調(diào)運子 View的measure方法,子View的measure中會回調(diào)子 View的onMeasure 方法 child.measure(childWidthMeasureSpec, childHeightMeasureSpec)

8、; 該方法就是對父視圖提供的measureSpe參數(shù)結(jié)合自身的LayoutParams參數(shù)進(jìn)行了調(diào)整, 然后再來調(diào)用child.measure(方法,具體通過方法 getChildMeasureSpe來進(jìn)行參數(shù)調(diào)整。 public static int getChildMeasureSpec(int spec, int padding, int childDimension) / 獲取當(dāng)前 Pare nt View 的 Mode 和 Size int specMode = MeasureSpec.getMode(spec); /獲取Pare nt size與paddi ng差值(也就是 Par

9、e nt剩余大小),若差值小于0直接返 回0 int size = Math.max(0, specSize - padding); / 定義返回值存儲變量 int resultSize = 0; int resultMode = 0; /依據(jù)當(dāng)前Pare nt的Mode進(jìn)行switch分支邏輯 switch (specMode) / Parent has imposed an exact size on us / 默認(rèn) Root View 的 Mode 就是 EXACTLY case MeasureSpec.EXACTLY: if (childDimension = 0) /如果child的

10、layout_wOrh屬性在xml或者java中給予具體大 / 于等于 0 的數(shù)值 / 設(shè)置 child 的 size為真實 layout_wOrh 屬性值,mode 為 EXACTLY resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; else if (childDimension = LayoutParams.MATCH_PARENT) /如果child的layout_wOrh屬性在xml或者java中給予 /MATCH_PARENT / Child wants to be our size. So be it.

11、/ 設(shè)置 child 的 size為 size, mode 為 EXACTLY 精品 resultMode = MeasureSpec.EXACTLY; resultSize = size; else if (childDimension = LayoutParams.WRAP_CONTENT) / 如果 child 的 layout_wOrh 屬性在 xml 或者 java 中給予 /WRAP_CONTENT / 設(shè)置 child 的 size為 size, mode 為 AT_MOST / Child wants to determine its own size. It cant be

12、/ bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; break; / 其他 Mode 分支類似 /將mode與size通過MeasureSpe方法整合為32位整數(shù)返回 return MeasureSpec.makeMeasureSpec(resultSize, resultMode); 用 View 的 getMeasuredWidth(和 getMeasuredHeight(方法來獲取 View 測量的寬高,必 須保證這兩個方法在onM easure流程之后被調(diào)用才能返回有效值。 MeasureSpec

13、( View的內(nèi)部類)測量規(guī)格為 int型,值由高2位規(guī)格模式specMode和 低30位具體尺寸specSize組成。其中specMode只有三種值: 精品 MeasureSpec.EXACTLY /確定模式,父 View希望子 View的大小是確定的,由 specSize決定; MeasureSpec.AT_MOST /最多模式,父 View希望子 View的大小最多是 specSizef旨 定的值; MeasureSpec.UNSPECIFIED /未指定模式,父View完全依據(jù)子 View的設(shè)計值來決 疋; View繪制流程第二步:遞歸layout源碼分析 ViewGroup layo

14、uts: 謹(jǐn)歸遲更峑-Wo噸結(jié)構(gòu) Vie wG roup on Layout(); View layout; 精品 onLayoutO: ViewGroup 的 layout方法,如下: Override public final void layout(i nt l, i nt t, i nt r, int b) super.layout(l, t, r, b); 調(diào)運了 View 父類的 layout 方法,所以我們看下 View 的 layout 源碼,如下: public void layout(int l, int t, int r, int b) II實質(zhì)都是調(diào)用setFrame方

15、法把參數(shù)分別賦值給 mLeft、mTop、mRight和/mBottom 這幾個變量 / 判斷 View 的位置是否發(fā)生過變化,以確定有沒有必要對當(dāng)前的 View 進(jìn)行重新 /layout boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed | (mPrivateFlags /ViewGroup 的 onLayout 方法,如下: Override protected abstract void onLayout(bool

16、ean changed, int l, int t, int r, int b); 關(guān)于 getWidth()、getHeight()和 getMeasuredWidth(、getMeasuredHeight(這兩對方法之間的 區(qū)別 public final int getMeasuredWidth () return mMeasuredWidth public final int getMeasuredHeight() return mMeasuredHeight public final int getWidth() return mRight - mLeft; public final

17、int getHeight() return mBottom - mTop; View.layout 方法可被重載, ViewGroup.layout 為 final 的不可重載,ViewGroup.onLayout 為abstract的,子類必須重載實現(xiàn)自己的位置邏輯。 凡是layout_XXX的布局屬性基本都針對的是包含子View的ViewGroup的,當(dāng)對一個 沒有父容器的 View 設(shè)置相關(guān) layout_XXX 屬性是沒有任何意義的 使用View的getWidth()和 getHeight()方法來獲取View測量的寬高,必須保證這兩個方 法在on Layout流程之后被調(diào)用才能返回

18、有效值 View繪制流程第三步:遞歸draw源碼分析 ViewGroup沒有重寫View的draw方法,所以如下直接從 View的draw方法開始 public void draw(Ca nvas can vas) / Step 1, draw the backgro un d, if n eeded if (!dirtyOpaque) drawBackgro un d(ca nvas); / skip step 2 / Step 3, draw the content if (!dirtyOpaque) on Draw(ca nvas); / Step 4, draw the childre

19、 n dispatchDraw(ca nvas); / Step 5, draw the fade effect and restore layers if (drawTop) matrix.setScale(1, fadeHeight * topFadeStre ngth); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); / Step 6, draw decorations

20、(scrollbars) onDrawScrollBars(canvas); private void drawBackground(Canvas canvas) /獲取xml中通過android:background屬性或者代碼中 /setBackgroundColor()、setBackgroundResource等方法進(jìn)行賦值的背景 /Drawable final Drawable background = mBackground; /根據(jù)layout過程確定的View位置來設(shè)置背景的繪制區(qū)域 if (mBackgroundSizeChanged) background.setBound

21、s(0, 0, mRight - mLeft, mBottom - mTop); mBackgroundSizeChanged = false; rebuildOutline(); /調(diào)用Drawable的draw()方法來完成背景的繪制工作 background.draw(canvas); / 以我 /View的onDraw方法,這是一個空方法。因為每個View的內(nèi)容部分是各不相同的, 所以需要由子類去實現(xiàn)具體邏輯。 protected void onDraw(Canvas canvas) / View 的dispatchDraw()方法是一個空方法, 如果View包含子類需要重寫他,所 們

22、有必要看下ViewGroup的dispatchDraw方法源碼 Override protected void dispatchDraw(Canvas canvas) final int childrenCount = mChildrenCount; final View children = mChildren; for (int i = 0; i = 0; i-) more |= drawChild(canvas, child, drawingTime); / ViewGroup確實重寫了 View的dispatchDraw()方法,該方法內(nèi)部會遍歷每個子/View , 然后調(diào)用drawC

23、hild()方法,我們可以看下 ViewGroup的drawChild方法 protected boolean drawChild(Canvas canvas, View child, long drawingTime) return child.draw(canvas, this, drawingTime); drawChild()方法調(diào)運了子 View的draw()方法。所以說 ViewGroup類已經(jīng)為我們重寫了 dispatchDraw()的功能實現(xiàn),我們一般不需要重寫該方法,但可以重載父類函數(shù)實現(xiàn)具體 的功能。 在獲取畫布剪切區(qū)時會自動處理掉padding,子View獲取Canvas

24、不用關(guān)注這些邏輯, 只用關(guān)心如何繪制即可。 默認(rèn)情況下子 View 的 ViewGroup.drawChild 繪制順序和子 View 被添加的順序一致, 但是你也可以重載 ViewGroup.getChildDraw in gOrder()方法提供不同順序。 iew的in validate方法源碼分析 View類中的一些in validate方法 /This must be called from a UI thread. To call from a non-Ul thread, / call post In validate。 public void in validate(Rect d

25、irty) final int scrollX = mScrollX; final int scrollY = mScrollY; /實質(zhì)還是調(diào)運invalidateInternal方法 in validate Intern al(dirt yeft - scrollX, dirty.top - scrollY, dirty.right - scrollX, dirty.bottom - scrollY, true, false); /This must be called from a UI thread. To call from a non-Ul thread, / call post

26、In validate() public void in validate(i nt l, i nt t, i nt r, int b) final int scrollX = mScrollX; final int scrollY = mScrollY; /實質(zhì)還是調(diào)運invalidateInternal方法 in validate Intern al(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); /This must be called from a UI thread. To call from a n

27、on-Ul thread, / call postInvalidate() public void invalidate() /invalidate 的實質(zhì)還是調(diào)運 invalidateInternal 方法 invalidate(true); /this function can be called with invalidateCache set to false to /skip that invalidation step void invalidate(boolean invalidateCache) / 實質(zhì)還是調(diào)運 invalidateInternal 方法 invalidate

28、Internal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); / 所有 invalidate 的最終調(diào)運方法 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) / Propagate the damage rectangle to the parent view. final AttachInfo ai = mAttachInfo; final ViewParent

29、 p = mParent; if (p != null / 設(shè)置刷新區(qū)域 / 傳遞調(diào)運 Parent ViewGroup 的 invalidateChild 方法 damage.set(l, t, r, b); p.invalidateChild(this, damage); View的in validate in validatel nter nal)方法實質(zhì)是將要刷新區(qū)域直接傳遞給了父ViewGroup 的 in validateChild 方法,在 in validate 中,調(diào)用父 View 的 in validateChild,這是一個從當(dāng)前 向上級父 View 回溯的過程 View

30、Group 的 invalidateChild 方法 public final void in validateChild(View child, final Rect dirty) ViewParent parent = this; final Attachlnfo attachlnfo = mAttachlnfo; do / 循環(huán)層層上級調(diào)運,直到 ViewRootlmpl 會返回 null parent = parent.invalidateChildlnParent(location, dirty); while (parent != null); 最后傳遞到 ViewRootlmpl

31、 的 invalidateChildlnParent 方法結(jié)束, 所以我們看下 ViewRootImpl 的 invalidateChildInParent方法 精品 public ViewParent invalidateChildlnParent(int location, Override Rect dirty) /View調(diào)運in validate最終層層上傳到 ViewRootlmpI后最終觸發(fā)了該方法 scheduleTraversals(); return n ull; 這個 ViewRootlmpI 類的 invalidateChildInParent方法直接返回了 null,

32、結(jié)束了那個 do while 循環(huán)。scheduleTraversal會通過 Handler 的 Runnable發(fā)送一個異步消息,調(diào)運 doTraversal 方法,然后最終調(diào)用 performTraversals(執(zhí)行重繪。所以說 View調(diào)運in validate方法的實 質(zhì)是層層上傳到父級,直到傳遞到ViewRootImpl后觸發(fā)了 scheduleTraversals方法,然后 整個View樹開始重新按照上面分析的View繪制流程進(jìn)行重繪任務(wù)。 View的post In validate方法源碼分析 in validate方法只能在UI Thread中執(zhí)行,其他線程中需要使用post

33、I nvalidate方法 public void post In validate() postI nvalidateDelayed(O); public void post In validateDelayed(l ong delayMillisec on ds) 精品 final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); public void dispat

34、chInvalidateDelayed(View view, long delayMilliseconds) Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); mHandler.sendMessageDelayed(msg, delayMilliseconds); 調(diào)運的 ViewRootlmpI 類的 dispatchlnvalidateDelayec方法,通過 ViewRootlmpI 類的 Handler 發(fā)送了一條 MSG_INVALIDATE 消息 , 繼續(xù)追蹤這條消息的處理可以發(fā)現(xiàn): public void handleMessage(Message msg) switch (msg.what) case MSG_lNVALlDATE: (View)msg.obj).invalidate(); break; invalidate 系列方法請求重繪 View 樹(也就是 d

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論