Android 自定義View知識點

自定義View知識點

自定義View我們需要了解View的繪製機制和ViewGroup的繪製機制,瞭解之後我們就可以在系統預留的方法裏進行自定義View的工作了。

1、MeasureSpec

模式 說明
UNSPECIFIED 父容器不對View有任何限制,給它想要的任何尺寸。一般用於系統內部,表示一種測量狀態。
EXACTLY 父容器已經檢測出view的精確大小,這時候view的大小就是size所指定的值。它對應於LayoutParams中的match_parent和具體數值兩種模式。
AT_MOST 父容器指定了一個可用大小,即size,子view的大小不能大於這個值,具體值要看vew的實現。它對應於LayoutParams中的wrap_content。

MeasureSpec是受到自身的LayoutParams和父容器的MeasureSpec共同影響的。

2、Measure

1、View的Measure過程

1.View調用onMeasure方法,onMeasure方法裏調用了setMeasuredDimension方法,setMeasuredDimension方法又調用了getDefaultSize方法。

2.調用setMeasuredDimension方法,該方法是用來設置View的寬高的。

3.setMeasuredDimension方法調用了getDefaultSize方法,該方法根據傳入的不同的MeasureSpec和size進行測量返回不同的測量結果。在AT_MOST和EXACTLY模式下,返回MeasureSpec.getSize方法返回的值,在UNSPEXIFIED方法裏返回傳入的大小值。根據上面的MeasureSpec表可知,對於直接繼承View自定義的View而言,wrap_content和match_parent是一樣的,所以我們要重寫onMeasure方法。

4.getDefaultSize方法傳入的參數調用了getSuggestedMinimumWidth()和getSuggestedMinimumHeight()方法。這兩個方法會根據View是否有背景來返回測量的值。如果沒有背景則返回mMinWidth或者mMinHeight,mMin的值是可以在View裏設置的,通過setMinimumWidth或者setMinimumHeight即可設置;如果有背景則返回mMinWidth或者mMinHeight和mBackground.getMinimumWidth或mBackground.getMinimumHeight中的最大值。

2、ViewGroup的Measure過程

1.ViewGroup不只要測量自身,還要便利測量子元素的measure方法。ViewGroup裏沒有提供onMeasure方法,但是它有measureChildren方法。

2.在measureChildren方法裏面它調用了getChildMeasureSpec方法。有意思的是我們可以在這張表裏找到一個switch語句,裏面有父View和子View測量模式最終返回的不同的結果,如圖所示

父View測量模式 子View LayoutParams 最終測量模式
EXACTLY 具體值 EXACTLY
EXACTLY MATCH_PARENT EXACTLY
EXACTLY WRAP_CONTENT AT_MOST
AT_MOST 具體值 EXACTLY
AT_MOST MATCH_PARENT AT_MOST
AT_MOST WRAP_CONTENT AT_MOST
UNSPECIFIED 具體值 EXACTLY
UNSPECIFIED MATCH_PARENT UNSPECIFIED
UNSPECIFIED WRAP_CONTENT UNSPECIFIED

需要注意的是,當父容器的測量模式爲AT_MOST時,子View的LayoutParams爲WRAP_CONTENT,根據上圖則可以發現子元素的測量模式也是AT_MOST,要解決這個問題需要在LayoutParams裏制定以下默認的寬和高。

3、Layout

layout方法的作用是確定View的位置。
layout有四個參數,分別是l、t、r、b分帶是View從左上右下相對其父容器的位置。layout方法會調用setFrame方法,而setFrame方法也有四個參數,正是layout方法穿進去的四個參數。調用setFrame方法後會調用onLayout方法,而onLayout方法是個空方法。需要我們根據不同的需求去實現。

4、Draw

draw的流程如下:
1、繪製 backgroud(drawBackground) ;
2、如果需要的話,保存canvas的layer,來準備fading ;
3、繪製view的content(onDraw方法);
4、繪製children(dispatchDraw方法);
5、如果需要的話,繪製fading edges,然後還原layer ;
6、繪製裝飾器、比如scrollBar(onDrawForeground);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章