android自定義View

相關的類:

------------------------------------------------------------------------------------------------------------------------------------------------------------------
View  

android中所有的可視組件都繼承自View,View定義了很多callbacks來定義它的行爲,如onDraw(),onMeasure()等。

ViewParent (interface)    

ViewParent爲所有想扮演其他views的父親的類定義了協議。

ViewGroup (extends View and implements ViewParent)    

所有Layout都繼承自ViewGroup,如LinearLayout。它負責在XML中定義Layout,擺放controls(views)到正確的位置。

它還負責child views的背景和動畫。

ViewRoot (implements ViewParent)     

ViewRoot相當於中央控制樞紐,他是activity中所有view的根父類。它的職責是:1.ViewRoot調度遍歷所有的views爲了把

views以正確的尺寸擺放到正確的位置,這一階段叫做layout階段;2.ViewRoot遍歷view的層級,爲了把views畫出來,

這一階段叫做drawing階段


Layout 階段: Measure + Layout

------------------------------------------------------------------------------------------------------------------------------------------------------------------

在Layout階段ViewRoot只會遍歷那些請求layout變化的views,這種條件遍歷是爲了節省資源,提高響應時間。想改變layout的

view只需callrequestLayout()方法。這個call會沿着view層級一直往上走,直到到達ViewRoot。然後ViewRoot在main線程隊列裏

調度佈局遍歷的消息。


layout階段分兩步走,measure + layout 。


measure由View Class的measure()函數實現。此函數的簽名是:

public final void measure(int widthMeasureSpec, int heightMeasureSpec) 。

measure()做一些整理打掃之類的工作,然後call 衍生類(暫且叫它SubViews)的onMeasure()方法。SubViews通過call 

setMeasuredDimension() 方法來設置它的尺寸。這些被設置到SubViews 的尺寸會被layout利用。在此上下文中,你只需override 

View.onMeasure()方法( onMeasure()方法有缺省實現,缺省實現通過layout files 來決定你的view的尺寸)。大部分情況下你只需

關心onMeasure()方法就足夠了,但如果你自定義ViewGroup,你就需要在你的onMeasure() 方法裏call 每個child views 的measure()方法。

measure 之後每個view 都知道了自己的尺寸,然後控制權交到layout。


layout 由layout() 實現,它的方法簽名是:

public void layout(int left, int top, int right, int bottom)  

layout() 會先後callonSizeChanged() onLayout() 方法。它們的簽名如下:

protected void onSizeChanged(int w, int h, int oldw, int oldh);      

protected void onLayout(boolean changed, int left, int top, int right, int bottom)
layout() call onLayout() 來允許像ViewGroup 在它的子views 裏call layout() 。至此Layout階段完成。


Drawing 階段

------------------------------------------------------------------------------------------------------------------------------------------------------------------

draw 的遍歷由View.draw()實現,draw()方法要做的事情有:

  • Draw the background
  • Draw view's content by delegating to onDraw()
  • Draw children by delegating to dispatchDraw()
  • Draw decorations such as scroll bars
儘管draw() 是一個public 方法,你卻不應該override 它,因爲draw() 實現了base View定義的協議。你應該override是:
  • public void onDraw(...)
  • public void dispatchDraw(...)
正如layout 階段由requestLayout() 觸發,draw 階段由invalidate()觸發。當你invalidate 了一個view,它就沿視圖層級鏈找到
ViewRoot ,由ViewRoot 負責遍歷調度。如果view 沒有請求invalidate 或它的位置和尺寸都沒有變,onDraw() 也許不會被view 調用。
然而,如果view 的位置或尺寸改變,base view 會調用此view 的invalidate 。


總結:

------------------------------------------------------------------------------------------------------------------------------------------------------------------

自定義view 用到的方法如下:
  • onMeasure
  • onSizeChanged
  • onLayout
  • onDraw
  • dispatchDraw
所有這些方法都是回調函數。尤其是onMeasure(), onLayout(), and onDraw() 對應着“protocol” or “template” 方法: measure(), layout(), draw() 。

這種模式叫做template/hook ,例如draw() 是template 方法,它以某種方式固定了行爲,然而又依賴hook onDraw() 來特殊化它自己。


當你自定義的view 沒有children 時,需要overridden 的方法是:
  • onMeasure(...)
  • onDraw(...)
有時也會用到onSizeChanged() 。

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