Android 的 View 焦點尋址

版權聲明:android

本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。算法

未經容許,不得轉載。3d

1、前言

Android 系統的智能電視,最近兩年基本上愈來愈火了,而在如今手機 App 開發中,都是使用觸摸的模式進行操做,可是在開發智能電視 App 的時候,View 的焦點尋址,就是咱們繞不過去的坎。cdn

那麼,本文就 View 如何控制 Focus,來分析它背後的實現邏輯。blog

2、View 的焦點控制

在 Android 中,是有一套本身的焦點查找的算法,簡單來講,就近原則,就是按方向就近查找下一個符合條件的 View。接口

若是咱們有對一個 View 焦點控制的需求,須要對這個 View 強制指定它上下左右以後的下一個獲取焦點的 View。能夠經過 View 的屬性來控制,只須要在對應方向上設定咱們須要焦點轉移的下一個 View 的 ID 便可。ci

  • android:nextFocusDown:按下的時候,焦點尋址的 ViewId。
  • android:nextFocusUp:按上的時候,焦點尋址的 ViewId。
  • android:nextFocusLeft:按左的時候,焦點尋址的 ViewId。
  • android:nextFocusRight:按右的時候,焦點尋址的 ViewId。
  • android:nextFocusForward:向前的時候,焦點尋址的 ViewId。

這些都是最基本的,不是本文的主題。那麼若是沒有設定這些屬性,而 Android 對 View 的就近原則的焦點查找算法,究竟是如何實現的呢?開發

3、View 的焦點尋址

Android 中,是如何作到對 View 焦點的控制呢?源碼

咱們就先從 View 的源碼看起,看看它是如何找到「下一個」位置的 View的,在 View 中,查找下一個應該獲取焦點的 View ,使用的方法是 focusSearch()。it

f-fsearch.png

它須要傳遞一個 direction 參數,這個 direction 就是指定獲取什麼方向上的下一個位置的焦點。

而 View 並不會處理焦點尋址的具體邏輯,而是將焦點的查找委託給 mParent 來實現,mParent 是一個接口,它的實現類是 ViewRootImpl。

f-vsearch.png

ViewRootImlp.focusSearch() 最終又將焦點尋址的任務,交託給 FocusFinder 來處理。

f-nextSearch.png

findNextFocus() 中能夠看到,findNextUserSpecifiedFocus() 方法正是用於查找咱們對 View 設定不一樣方向的下一個焦點的 ViewId ,它的優先級是最高的,若是沒有找到,纔會進行 findNextFocus() 經過算法來查找對應的 View。

爲了證明這個說法,咱們先看看 findNextUserSpecifiedFocus() 的源碼。

f-user.png

最終,又調回到 View.findUserSetNextFocus() 方法去尋找。

f-viewuser.png

到這裏也證明了咱們的猜想,確實是經過 direction 來進行 View 的焦點尋址。

再回過頭來看看 findNextFocus() 方法,若是經過 findNextUserSpecifiedFocus() 方法沒有找到咱們指定的 View,就會繼續向下執行。這裏聲明的一個局部變量 focusables 就是用於存放符合算法的全部 View 。

接下來再看看如何向 focusables 這個 List 中,添加符合尋址要求的 View。在 findNextFocus() 中能夠看到,它最終會調用 findNextFocusInAbsoluteDirection() 方法。

f-findnext.png

從 findNextFocusInAbsoluteDirection() 方法能夠看出,就近原則就是在這裏實現的,經過 View 的座標點,計算出最符合要求的 View ,最終將找到的 View 返回過去。

f-abs.png

到這裏,基本就追蹤到 View 對焦點尋址的完整邏輯。最後補一個方法調用的流程圖。

f-tu.png

4、總結

若是有對 View 焦點的控制,能夠考慮經過設置 View 的屬性,還能夠經過重寫 View.focusSearch() 方法,來定製 View 焦點的尋址規則。不過通常而言,不推薦重寫 focusSearch() 方法,只使用屬性控制也能知足咱們的需求。

公衆號二維碼.jpg
相關文章
相關標籤/搜索