概念
Android中的View包含了用戶交互和顯示,類似于Windows操作系統(tǒng)中的window掏颊。
ViewGroup是View的子類糟红,所以它也具有View的特性艾帐,但它主要用來充當View的容器,將其中的View視作自己的孩子盆偿,對它的子View進行管理柒爸,當然它的孩子也可以是ViewGroup類型。
ViewGroup(樹根)和它的孩子們(View和ViewGroup)以樹形結(jié)構(gòu)形成了一個層次結(jié)構(gòu)陈肛,View類有接受和處理消息的功能揍鸟,android系統(tǒng)所產(chǎn)生的消息會在這些ViewGroup和 View之間傳遞。
Android的窗口系統(tǒng)
Android的窗口系統(tǒng)是Client/Server模式的句旱。所提到的概念:View阳藻,ViewGroup,DecorView谈撒,ViewRoot都是存在于窗口系統(tǒng)的Client端腥泥。
Android中的Window是表示Top Level等頂級窗口的概念。DecorView是Window的Top-Level View啃匿,這個View可以稱之為主View蛔外,DecorView會缺省的attach到Activity的主窗口中。
ViewRoot建立了主View(DecorView)與窗口系統(tǒng)Server端的通訊橋梁, ViewRoot是 Handler的子類溯乒,即它其實是個Handler夹厌,它接受窗口系統(tǒng)服務(wù)器端的消息并將消息投遞到窗口系統(tǒng)的客戶端,然后消息就從客戶端的主View往其下面的子View傳遞裆悄,直到消息被完全處理掉為止矛纹。
ViewRoot建立了主View(DecorView)與窗口系統(tǒng)Server端的通訊橋梁, ViewRoot是 Handler的子類,即它其實是個Handler光稼,它接受窗口系統(tǒng)服務(wù)器端的消息并將消息投遞到窗口系統(tǒng)的客戶端(圖1)或南,然后消息就從客戶端的主View往其下面的子View傳遞,直到消息被完全處理掉為止艾君。
DecorView實際上是一個ViewGroup采够。在依存關(guān)系上來講,對單個主窗口來講冰垄,DecorView是Top-Level View蹬癌。View并不是關(guān)注的重點,重要的是我們需要知道消息分發(fā)路徑是建立在什么關(guān)系上的虹茶。View的成員變量mParent用來管理View上級關(guān)系的冀瓦。而ViewGroup顧名思義就是一組View的管理,于是在ViewGroup構(gòu)建了焦點管理和子View節(jié)點數(shù)組写烤。這樣通過View的mParent和ViewGroup的mChildren構(gòu)建了Android中View直接的關(guān)系網(wǎng)翼闽。
View
繪制流程
繪制按照視圖樹的順序執(zhí)行。視圖繪制時會先繪制子控件洲炊。如果視圖的背景可見感局,視圖會在調(diào)用onDraw函數(shù)之前繪制背景尼啡。強制重繪,可以使用invalidate()询微。
事件的基本流程如下:
- 事件分配給相應(yīng)視圖崖瞭,視圖處理它,并通知相關(guān)監(jiān)聽器撑毛。
- 操作過程中如果發(fā)生視圖的尺寸變化书聚,則該視圖用調(diào)用requestLayout()方法,向父控件請求再次布局藻雌。
- 操作過程中如果發(fā)生視圖的外觀變化雌续,則該視圖用調(diào)用invalidate()方法,請求重繪胯杭。
- 如果requestLayout()或invalidate()有一個被調(diào)用驯杜,框架會對視圖樹進行相關(guān)的測量、布局和繪制做个。
注意鸽心,視圖樹是單線程操作,直接調(diào)用其它視圖的方法必須要在UI線程里居暖⊥缙担跨線程的操作必須使用句柄Handler。
焦點處理:
框架處理焦點的轉(zhuǎn)移太闺,來響應(yīng)用戶輸入冲九。isFocusable()函數(shù)表示視圖是否能接受焦點。setFocusable(boolean)函數(shù)可以改變視圖能否接受焦點跟束。觸摸屏模式(Touch Mode)的相關(guān)函數(shù)是isFocusableInTouchMode()和setFocusableInTouchMode(boolean)。
焦點轉(zhuǎn)移按照就近算法丑孩。按哪個方向就近可以在XML布局文件中配置冀宴。
nextFocusDown
nextFocusLeft
nextFocusRight
nextFocusUp
視圖請求焦點可以使用requestFocus()。
類成員介紹
protected ViewParent mParent;
用于記錄其父目錄温学,就是前面提到的ViewGroup略贮;
protected OnClickListener mOnClickListener;
click事件的回調(diào)接口.
public void draw(Canvas canvas)
這個函數(shù)用于渲染View和它的孩子,我們不應(yīng)該在子類對它進行override仗岖。
protected void onDraw(Canvas canvas)
我們一般override此函數(shù)來實現(xiàn)自己的繪制操作逃延。
IWindowSession getWindowSession() {
return mAttachInfo != null ? mAttachInfo.mSession : null;
}
函數(shù)getWindowSession()用于得到窗口系統(tǒng)Client端和服務(wù)器端通訊的接口IWindowSession。這是一個AIDL接口轧拄,android系統(tǒng)中的跨進程通訊就是用AIDL接口實現(xiàn)的揽祥。
public final void layout(int l, int t, int r, int b)
此函數(shù)用于確定View和其子View的尺寸和位置,它的調(diào)用發(fā)生在onMeasure之后檩电。
** protected void onLayout(boolean changed, int left, int top, int right, int bottom)**
此函數(shù)在layout調(diào)用完成后執(zhí)行拄丰,View的子類一般override此函數(shù)府树,并在函數(shù)中對其每個孩子調(diào)用layout方法。
public View getRootView()
此函數(shù)用于得到View層次結(jié)構(gòu)的top-level View料按,即上文中提到的DecorView奄侠。
public final void measure(int widthMeasureSpec, int heightMeasureSpec)
此函數(shù)用戶找出View的大小,它的參數(shù)widthMeasureSpec载矿、heightMeasureSpec是其父親傳遞給它的垄潮,這2個參數(shù)是View找出其大小時的限制條件,其實真正的精確大小確定是由onMeasure()完成的闷盔,onMeasure由measure函數(shù)調(diào)用弯洗。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
此函數(shù)測量View并根據(jù)其內(nèi)容來決定View的高和寬,它應(yīng)該被子類override以實現(xiàn)大小的精確測量馁筐。在onMeasure中我們必須調(diào)用View.setMeasuredDimension(int, int)來保存測量得到的大小,高和寬分別被保存在View.mMeasuredHeight和View.mMeasureWidth中涂召。
public boolean onKeyUp(int keyCode, KeyEvent event)
此函數(shù)會在鍵盤按鍵釋放后被調(diào)用,但前提是View必須獲得焦點敏沉。
public boolean onTouchEvent(MotionEvent event)
此函數(shù)用于響應(yīng)觸摸屏事件果正。
public void invalidate()
此函數(shù)將調(diào)用onDraw,強制重繪盟迟。
public void requestLayout()
當某些東西發(fā)生改變后秋泳,當前View層次結(jié)構(gòu)無效了,調(diào)用此函數(shù)對View的層次結(jié)構(gòu)進行重新布局攒菠。
ViewGroup
ViewGroup繼承于View迫皱,它可以包含其他的View,就像一個View的容器辖众,我們可以調(diào)用其成員函數(shù)addView()將View當作孩子放到ViewGroup中卓起。
我們經(jīng)常使用的LinearLayout、relativeLayout等都是ViewGroup的子類凹炸,ViewGroup類中有一個內(nèi)部類ViewGroup.LayoutParams戏阅,我們經(jīng)常使用LayoutParams的子類來構(gòu)造布局參數(shù)。
我們也可以自定義自己的布局啤它,以方便日后使用和維護奕筐,這時我們就需要繼承ViewGroup類并在派生類中重寫ViewGroup的一些方法.