Android View 焦點(diǎn)尋址的來(lái)龍去脈 ?。。?/h1>
一、前言
Android 系統(tǒng)的智能電視,最近兩年基本上越來(lái)越火了,而在現(xiàn)在手機(jī) App 開(kāi)發(fā)中,都是使用觸摸的模式進(jìn)行操作,但是在開(kāi)發(fā)智能電視 App 的時(shí)候,View 的焦點(diǎn)尋址,就是我們繞不過(guò)去的坎。
那么,本文就 View 如何控制 Focus,來(lái)分析它背后的實(shí)現(xiàn)邏輯。
二、View 的焦點(diǎn)控制
在 Android 中,是有一套自己的焦點(diǎn)查找的算法,簡(jiǎn)單來(lái)說(shuō),就近原則,就是按方向就近查找下一個(gè)符合條件的 View。
如果我們有對(duì)一個(gè) View 焦點(diǎn)控制的需求,需要對(duì)這個(gè) View 強(qiáng)制指定它上下左右之后的下一個(gè)獲取焦點(diǎn)的 View??梢酝ㄟ^(guò) View 的屬性來(lái)控制,只需要在對(duì)應(yīng)方向上設(shè)定我們需要焦點(diǎn)轉(zhuǎn)移的下一個(gè) View 的 ID 即可。
- android:nextFocusDown:按下的時(shí)候,焦點(diǎn)尋址的 ViewId。
- android:nextFocusUp:按上的時(shí)候,焦點(diǎn)尋址的 ViewId。
- android:nextFocusLeft:按左的時(shí)候,焦點(diǎn)尋址的 ViewId。
- android:nextFocusRight:按右的時(shí)候,焦點(diǎn)尋址的 ViewId。
- android:nextFocusForward:向前的時(shí)候,焦點(diǎn)尋址的 ViewId。
這些都是最基本的,不是本文的主題。那么如果沒(méi)有設(shè)定這些屬性,而 Android 對(duì) View 的 就近原則 的焦點(diǎn)查找算法,到底是如何實(shí)現(xiàn)的呢?
三、View 的焦點(diǎn)尋址
Android 中,是如何做到對(duì) View 焦點(diǎn)的控制呢?
我們就先從 View 的源碼看起,看看它是如何找到“下一個(gè)”位置的 View的,在 View 中,查找下一個(gè)應(yīng)該獲取焦點(diǎn)的 View ,使用的方法是 focusSearch()。
它需要傳遞一個(gè) direction 參數(shù),這個(gè) direction 就是指定獲取什么方向上的下一個(gè)位置的焦點(diǎn)。
而 View 并不會(huì)處理焦點(diǎn)尋址的具體邏輯,而是將焦點(diǎn)的查找委托給 mParent 來(lái)實(shí)現(xiàn),mParent 是一個(gè)接口,它的實(shí)現(xiàn)類(lèi)是 ViewRootImpl。
ViewRootImlp.focusSearch() 最終又將焦點(diǎn)尋址的任務(wù),交托給 FocusFinder 來(lái)處理。
findNextFocus()中可以看到,findNextUserSpecifiedFocus() 方法正是用于查找我們對(duì) View 設(shè)定不同方向的下一個(gè)焦點(diǎn)的 ViewId ,它的優(yōu)先級(jí)是***的,如果沒(méi)有找到,才會(huì)進(jìn)行 findNextFocus() 通過(guò)算法來(lái)查找對(duì)應(yīng)的 View。
為了證實(shí)這個(gè)說(shuō)法,我們先看看 findNextUserSpecifiedFocus()的源碼。
最終,又調(diào)回到 View.findUserSetNextFocus() 方法去尋找。
到這里也證實(shí)了我們的猜測(cè),確實(shí)是通過(guò) direction 來(lái)進(jìn)行 View 的焦點(diǎn)尋址。
再回過(guò)頭來(lái)看看 findNextFocus() 方法,如果通過(guò) findNextUserSpecifiedFocus() 方法沒(méi)有找到我們指定的 View,就會(huì)繼續(xù)向下執(zhí)行。這里聲明的一個(gè)局部變量 focusables 就是用于存放符合算法的所有 View 。
接下來(lái)再看看如何向 focusables 這個(gè) List 中,添加符合尋址要求的 View。在 findNextFocus() 中可以看到,它最終會(huì)調(diào)用 findNextFocusInAbsoluteDirection() 方法。
從 findNextFocusInAbsoluteDirection() 方法可以看出,就近原則就是在這里實(shí)現(xiàn)的,通過(guò) View 的坐標(biāo)點(diǎn),計(jì)算出***要求的 View ,最終將找到的 View 返回過(guò)去。
到這里,基本就追蹤到 View 對(duì)焦點(diǎn)尋址的完整邏輯。***補(bǔ)一個(gè)方法調(diào)用的流程圖。
四、總結(jié)
如果有對(duì) View 焦點(diǎn)的控制,可以考慮通過(guò)設(shè)置 View 的屬性,還可以通過(guò)重寫(xiě) View.focusSearch() 方法,來(lái)定制 View 焦點(diǎn)的尋址規(guī)則。不過(guò)一般而言,不推薦重寫(xiě) focusSearch() 方法,只使用屬性控制也能滿(mǎn)足我們的需求。
【本文為51CTO專(zhuān)欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)微信公眾號(hào)聯(lián)系作者獲取授權(quán)】