View的繪制過程

View的繪制包括如下三個過動作:

動作 調(diào)用方法 功能
Measure onMeasure() 測量得到該控件的長和寬
Layout onLayout() 指定子控件的擺放位置(ViewGroup必須實現(xiàn))
Draw onDraw() 進行實際繪制

注意:View的繪制過程在Activity的onResume()方法之后才進行,即onMeasure()onLayout()onDraw()方法在onResume()方法之后執(zhí)行

  • Measure --(onMeasure(int widthMeasureSpec,int heightMeasureSpec))

    1. View進行繪制前,首先會調(diào)用Measure(int widthMeasureSpec,int heightMeasureSpec)方法對控件的寬高進行測量確定,而Measure()實際通過調(diào)用onMeasure(int widthMeasureSpec,int heightMeasureSpec)方法完成測量,并將測量的寬高最終通過setMeasuredDimension(measuredWidth,measuredHeight)方法進行保存。

注意:測量動作完成后通過getMeasuredWidth()getMeasuredHeight()方法獲得的寬高值,即為此處設置的measuredWidth和measuredHeight。

2.onMeasure()方法中的兩個參數(shù)widthMeasureSpec,heightMeasureSpec封裝了父容器對View布局上的限制,內(nèi)部提供了寬高的信息(SpecMode,SpecSize),SpecSize是指在某種SpecMode下的參考尺寸,其中SpecMode有三種模式:

模式 含義
EXACTLY 父容器已經(jīng)檢測出view所需的大小
AT_MOST 父容器指定了一個大小, view 的大小不能大于這個值
UNSPECIFIED 父容器不對 view 有任何限制,要多大給多大

通過MeasureSpec.getMode(widthMeasureSpec)MeasureSpec.getSize(widthMeasureSpec)方法可分別獲得寬對應的模式和具體值。

對于應用層 View ,其 MeasureSpec 由父容器的 MeasureSpec 和自身 的 LayoutParams 來共同決定,針對不同的父容器和view本身不同的LayoutParams,view有多種MeasureSpec。其關系如下圖所示:

MeasureSpec.png

3.onMeasure()中measuredWidth和measuredHeight的計算方式,這里不做詳細分析,查看源碼再結合上面的MeasureSpec即可清楚。此處再概括一下Measure的測量流程,如下圖:

onMeasure測量流程.png
  • Layout--(onLayout(boolean changed,int l, int t, int r, int b))

    1. ViewGroup通過Layout()方法,來確定子元素的擺放位置。實際調(diào)用onLayout()來完成此動作。當viewgroup的位置被確定后,會在onLayout()方法中遍歷所有child并調(diào)用對應的layout(int l, int t, int r, int b)方法,從而確定子View的擺放位置。

    2.在Layout(boolean changed,int l, int t, int r, int b)方法中指定的l、t、r、b為子控件的相對于父控件擺放位置,如下圖所示,坐標原點為父控件的左上角。

onlayout.jpeg

注意:在View中getWidth()getHeight()獲得的寬高,為父控件指定的擺放位置的寬高,即width = right - left,height = bottom - top,與getMeasuredWidth()getMeasuredHeight()不同。一般來說,建議使用child.layout(0,0,chile.getMeasuredWidth(),child.getMeasureHeight())來指定子View的擺放位置。此時在子View中,getWidth() 與getMeasuredWidth()相等。

  • Draw--onDraw(Canvas canvas)

當測量(measure),和布局(layout)結束后,就進行View的繪制(draw)了,View通過draw(Canvas canvas)方法繪制圖像,實際調(diào)用的是onDraw(Canvas,canvas)方法。

draw 的大致流程:
a. 畫背景 background.draw(canvas)
b. 繪制自己( onDraw )
c. 繪制 children ( dispatchDraw )
d. 繪制裝飾( onDrawScrollBars )
備注:dispatchDraw 會遍歷調(diào)用所有 child 的 draw ,如此 draw 事件就一層層地傳遞了下去

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容