自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android View焦點(diǎn)總結(jié)

移動(dòng)開發(fā) Android
Android焦點(diǎn)相關(guān)邏輯大部分都在都在View, ViewGroup和FocusFinder三個(gè)類中。View對(duì)象都有一個(gè)mParent變量(添加到ViewGroup后), 代指其父容器. 絕大部分View的mParent都是ViewGroup類型, 除了根節(jié)點(diǎn)。一個(gè)Window中View根節(jié)點(diǎn)DecorView的mParent稱為ViewRoot, 在安卓4.0后ViewRoot對(duì)應(yīng)ViewRootImpl, 它不是View的子類, 而是個(gè)ViewParent。

Android View焦點(diǎn)

Android焦點(diǎn)相關(guān)邏輯大部分都在都在View, ViewGroup和FocusFinder三個(gè)類中.

ViewRoot

View對(duì)象都有一個(gè)mParent變量(添加到ViewGroup后), 代指其父容器. 絕大部分View的mParent都是ViewGroup類型, 除了根節(jié)點(diǎn). 一個(gè)Window中View根節(jié)點(diǎn)DecorView的mParent稱為ViewRoot, 在安卓4.0后ViewRoot對(duì)應(yīng)ViewRootImpl, 它不是View的子類, 而是個(gè)ViewParent. ViewRootImpl是連接Window和DecorView的紐帶, View的焦點(diǎn), 按鍵, 布局, 渲染等流程都是從ViewRoot中開始的.

View的焦點(diǎn)

基本流程如下

 

 

View(包括ViewGroup)獲取焦點(diǎn)都通過(guò)如下三個(gè)方法

View.java 

 

 

 

從上面可以看到前兩個(gè)最終會(huì)執(zhí)行到第三個(gè)方法.

***的requestFocusNoSearch先判斷是否可以獲取焦點(diǎn), 然后進(jìn)入下面的***流程:

View.java 

 

 

 

上面的流程比較簡(jiǎn)單: 如果當(dāng)前沒(méi)有焦點(diǎn), 先置焦點(diǎn)標(biāo)志, 再通知parent, 然后刷新圖片.

主要的流程在mParent的requestChildFocus里面, 后面會(huì)分析. 那里會(huì)逐層向上修改焦點(diǎn)View并清除原來(lái)有焦點(diǎn)的View的焦點(diǎn)

onFocusChange會(huì)觸發(fā)invalidate刷新, 然后調(diào)用onFocusChangeListener. 默認(rèn)情況每個(gè)View只能設(shè)置一個(gè)onFocusChangeListener, 而開發(fā)中經(jīng)常遇到需要設(shè)置多個(gè)Listener的情況, 我們就可以重寫onFocusChange方法, 實(shí)現(xiàn)回調(diào)多個(gè)onFocusChangeListener的需求.

ViewGroup的焦點(diǎn)

ViewGroup獲取焦點(diǎn)是在View獲取焦點(diǎn)流程中多了內(nèi)部焦點(diǎn)處理

ViewGroup.java 

 

 

 

上面代碼中descendantFocusability決定了是先按View焦點(diǎn)流程處理(自己處理焦點(diǎn))還是先把給子View處理

FOCUS_BLOCK_DESCENDANTS 不允許子View獲取焦點(diǎn), 那么按照View的流程進(jìn)行

FOCUS_BEFORE_DESCENDANTS 先按照View的流程處理, 如果自己不能獲取焦點(diǎn)則給孩子處理

FOCUS_AFTER_DESCENDANTS 先嘗試給孩子焦點(diǎn), 如果沒(méi)有可獲取焦點(diǎn)再按照View流程自己獲取焦點(diǎn)

默認(rèn)值FOCUS_BEFORE_DESCENDANTS, 我們可以通過(guò)setDescendantFocusability(int d)

設(shè)置

onRequestFocusInDescendants方法是給子類重寫使用, 可以控制子View處理焦點(diǎn). 默認(rèn)按照子View順序處理, direction向下或向右則從***個(gè)開始, 向上或向左則從***一個(gè)開始, 直到某個(gè)子View獲取焦點(diǎn)

注意此方法只在此ViewGroup及其上層View上調(diào)用requestFocus時(shí)會(huì)執(zhí)行到

父容器焦點(diǎn)的處理

在View獲取焦點(diǎn)流程中會(huì)調(diào)用mParent.requestChildFocus, 維護(hù)View樹上焦點(diǎn)唯一, 在各層ViewGroup中保存有焦點(diǎn)的子View

ViewGroup.java 

 

 

 

先清除自己的焦點(diǎn), 如果原來(lái)內(nèi)部有焦點(diǎn), 先清除其焦點(diǎn), 保存獲取焦點(diǎn)的孩子, 然后調(diào)用上一層的requestChildFocus. ***的調(diào)用可知, 這個(gè)方法會(huì)一直調(diào)用到View的樹的root節(jié)點(diǎn).

在當(dāng)前ViewGroup內(nèi)部, 任何一個(gè)孩子取得焦點(diǎn)都會(huì)執(zhí)行到這個(gè)方法, 因此此方法也是ViewGroup得知孩子焦點(diǎn)變化的方法之一.(可惜不能得知孩子失去焦點(diǎn))

失去焦點(diǎn)或清除焦點(diǎn)

獲取焦點(diǎn)可以是主動(dòng)的, 但失去焦點(diǎn)一般都是被動(dòng)的(見上面的代碼), 因此邏輯相對(duì)簡(jiǎn)單, 只要清除焦點(diǎn)狀態(tài)即可.

ViewGroup.java 

 

 

 

View.java

 

 

注意上面的方法是默認(rèn)package訪問(wèn)級(jí)別的, 我們無(wú)法重寫也不能調(diào)用

也可以主動(dòng)清除焦點(diǎn), 與獲取焦點(diǎn)流程相似

ViewGroup.java 

 

 

 

View.java 

 

 

 

ViewGroup.java

以上是安卓View系統(tǒng)焦點(diǎn)處理的全部流程和涉及到的方法, ViewRootImpl的requestChildFocus和clearChildFocus實(shí)現(xiàn)我們不需要關(guān)注

另外還有以下一些輔助方法

boolean isFocusable() View是否可以獲取焦點(diǎn)

boolean isFocused() View是否獲取焦點(diǎn)

boolean hasFocus() View/ViewGroup內(nèi)部是否有焦點(diǎn)

View findFocus() 取到View/ViewGroup內(nèi)部的焦點(diǎn)View

View getFocusedChild() 取到ViewGroup內(nèi)部有焦點(diǎn)的子View

View getRootView() 取到根節(jié)點(diǎn)View(一般是DecorView或頂層ViewGroup)

焦點(diǎn)移動(dòng)

除了在代碼里面控制焦點(diǎn), 系統(tǒng)對(duì)沒(méi)有處理的方向鍵等一些按鍵自動(dòng)按照焦點(diǎn)移動(dòng)來(lái)處理, 見下面代碼

ViewRootImpl.java 

 

 

 

 

 

 

代碼比較上, 但是主要做了三個(gè)步驟

如果View沒(méi)有處理按鍵, 把上下左右tab等按鍵轉(zhuǎn)換成對(duì)應(yīng)方向

在當(dāng)前焦點(diǎn)View上通過(guò)focusSearch方法查找對(duì)應(yīng)方向的下一個(gè)View

查找到的View調(diào)用requestFocus因此主要的流程在focusSearch中

View.java 

 

 

 

普通View查找什么都沒(méi)做, 交給parent來(lái)完成.

ViewGroup.java 

 

 

 

ViewRootImpl 

 

 

 

 

我們可以重寫focusSearch控制焦點(diǎn)移動(dòng)順序, 而默認(rèn)的焦點(diǎn)移動(dòng)順序由FocusFinder決定

FocusFinder查找焦點(diǎn)

FocusFinder為public的工具類, 主要就兩個(gè)方法, 可以在給定的View內(nèi)在指定方向查找指定View或坐標(biāo)的下一個(gè)焦點(diǎn)如下: 

 

 

 

核心邏輯就兩步, 先查找setNextFocusXXId設(shè)置的View, 如果沒(méi)有按照就近算法查找.具體算法不再分析, SDK里面有源碼.

總結(jié)

綜合上面的流程分析, 我們?cè)趯?shí)現(xiàn)自定義View時(shí), 對(duì)焦點(diǎn)的特殊需求有如下思路

requestFocus和clearFocus直接對(duì)View清除或轉(zhuǎn)移焦點(diǎn)

除了onFocusChangeListener, 還可以在onFocusChange方法中實(shí)現(xiàn)一些View失去/獲得焦點(diǎn)時(shí)通知

對(duì)ViewGroup, 如果只需要在子View獲取焦點(diǎn)時(shí)得到通知, 有requestChildFocus方法.

重寫onRequestFocusInDescendants方法可以控制某些情景下ViewGroup焦點(diǎn)

控制焦點(diǎn)移動(dòng)可以重寫focusSearch方法

另外還有FocusFinder工具和上面的輔助方法.

責(zé)任編輯:龐桂玉 來(lái)源: Android開發(fā)中文站
相關(guān)推薦

2017-12-28 14:51:01

AndroidView焦點(diǎn)

2016-03-14 09:43:47

androidview總結(jié)

2013-07-16 14:47:18

Android EdiEditText不彈出Android開發(fā)

2011-01-26 10:21:30

view類Qt

2017-03-14 15:09:18

AndroidView圓形進(jìn)度條

2011-12-23 10:17:25

Android音樂(lè)編程管理音頻焦點(diǎn)

2016-12-26 15:25:59

Android自定義View

2016-11-16 21:55:55

源碼分析自定義view androi

2017-03-07 13:03:34

AndroidView知識(shí)問(wèn)答

2016-04-12 10:07:55

AndroidViewList

2014-07-29 15:57:01

ContentProv

2010-01-27 16:41:48

Android特點(diǎn)

2010-01-27 17:45:15

Android應(yīng)用技巧

2010-01-26 17:05:37

Android缺點(diǎn)

2011-11-04 16:34:20

控件Android

2017-08-21 21:36:23

AndroidViewJava

2016-12-12 14:55:01

AndroidAndroid Vie

2010-03-05 13:40:29

Android Vie

2015-06-17 10:24:47

Android面試

2018-01-09 15:57:18

熱修復(fù)開發(fā)編譯
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)