接下去應(yīng)該是梳理一下 Android Tv 主界面實(shí)現(xiàn)原理及解析的一個(gè)系列博客了,大體上的安排是先介紹 Google 官方提供的 Leanback 庫(kù)的使用,如何使用該庫(kù)來(lái)實(shí)現(xiàn)簡(jiǎn)單的 Home 界面,然后再去分析 Leanback 主界面實(shí)現(xiàn)的相關(guān)源碼,了解完 Google 是如何實(shí)現(xiàn)之后就可以扔掉 Leanback 自己來(lái)嘗試實(shí)現(xiàn),畢竟 Leanback 的可定制不高。
效果圖
首先貼幾張常見(jiàn)的 Home 界面效果:



第一張是愛(ài)奇藝 Tv 應(yīng)用的 Home 界面,第二張是一個(gè)開源 Demo 的 Home 界面,第三張是 Google 官方 Tv Sample 的 Home 界面。
比較常見(jiàn)的 Home 界面風(fēng)格應(yīng)該是第一張和第二張的形式,這兩種的 ui 實(shí)現(xiàn)也不一樣,因此我就想搞懂這兩種界面分別是如何實(shí)現(xiàn)的!!
目前重點(diǎn)研究第一張的實(shí)現(xiàn)方式吧,畢竟 Google 的 Leanback 庫(kù)實(shí)現(xiàn)出來(lái)的效果跟第一張有一些共同點(diǎn),因此可以從 Leanback 入手來(lái)學(xué)習(xí)它是如何實(shí)現(xiàn)的。而至于第二張的實(shí)現(xiàn)原理,目前還沒(méi)有思路,也暫時(shí)找不到相關(guān)資料來(lái)學(xué)習(xí),Github 上面的 demo 都是忽悠人,控件全都是在 xml 中直接寫死的,所以第二張圖的 Home 界面實(shí)現(xiàn)原理以后再慢慢研究吧,或者有讀者可以指點(diǎn)一二,非常感激。
分析
先大概的來(lái)分析一下第一張愛(ài)奇藝 Home 界面的實(shí)現(xiàn):

這個(gè)是 Tab 標(biāo)簽欄,選中不同的 Tab,內(nèi)容區(qū)會(huì)顯示不同的視頻列表,這里的實(shí)現(xiàn)應(yīng)該是 TabLayout + Fragment 的形式,或者 TabLayout + ViewPager,但 ViewPager 在 Tv 上使用好像會(huì)出很多坑。

這個(gè)是內(nèi)容區(qū)域即可左右滑動(dòng)又可上下滑動(dòng)的視頻列表區(qū)域,主頁(yè)最復(fù)雜的實(shí)現(xiàn)應(yīng)該就是這個(gè)地方了。要我實(shí)現(xiàn)的話,思路就是 RecyclerView 嵌套 RecyclerView 來(lái)實(shí)現(xiàn),先不談 RecyclerView 這種滑動(dòng)的控件在 Tv 上會(huì)出問(wèn)題,嵌套這個(gè)坑就足夠你填的了。
在 Tv 上,可以用 HorizontalGridView 和 VerticalGridView 替代 RecyclerView 使用。但要實(shí)現(xiàn)左右單行滑動(dòng),上下整體滑動(dòng)的效果,我只能想到上下用 VerticalGridView 來(lái)實(shí)現(xiàn),每一行是它 itemView,而每一行的實(shí)現(xiàn)則用 HorizontalGridView 來(lái)實(shí)現(xiàn)。也就是 1 個(gè) VerticalGridView + 多個(gè) HorizontalGridView 來(lái)實(shí)現(xiàn)。
但這樣的嵌套仍會(huì)有許多問(wèn)題出現(xiàn),比如快速移動(dòng)時(shí)的焦點(diǎn)丟失、性能問(wèn)題、每一行的 View 如何緩存、復(fù)用等。
有大佬清楚解決方案,或者有其他實(shí)現(xiàn)思路的小伙伴們歡迎指點(diǎn)一下,實(shí)在沒(méi)有,那就只能自己慢慢去啃 Leanback 的相關(guān)源碼,然后再來(lái)梳理一下了。
使用
不出意外,接下去的空閑時(shí)間應(yīng)該就是啃 Leanback Home 界面實(shí)現(xiàn)的相關(guān)源碼,在此之前,先了解一下 Leanback 如何使用,哪些類是重點(diǎn),后面分析時(shí)才方便入手。
以下是我覺(jué)得應(yīng)該理解的類:
- BrowerFragment:用來(lái)展示可左右上下滑動(dòng)的視頻列表界面
- ArrayObjectAdapter:作用類似于 List,可以用于裝每一行的數(shù)據(jù),也可以用于裝一行里的每一個(gè) item 數(shù)據(jù)
- ListRowPresenter:Leanback 庫(kù)中的 Presenter 作用都有些類似于 RecyclerView.Adapter
- ListRow:可以理解成一個(gè) Mode,也就是把每一行抽象封裝成一個(gè) ListRow
用法跟 RecyclerView 很像,就是可能單獨(dú)從命名上來(lái)理解會(huì)有些亂。只要你自己嘗試去利用 Leanback 去實(shí)現(xiàn)個(gè)最簡(jiǎn)單的 Home 界面,大體就能理解了。比如,要實(shí)現(xiàn)下面這個(gè) Home 界面:

首先,界面顯示的數(shù)據(jù)都存在 ArrayObjectAdapter 里面,在 RecyclerView 時(shí)我們是存在 ArrayList 里:

初始化 ArrayObjectAdapter 對(duì)象時(shí)需傳入一個(gè) Presenter 進(jìn)去,這里跟 RecyclerView 的使用有些不同,在 RecyclerView 里,我們是將 List 對(duì)象傳給 Adapter,讓 Adapter 去將數(shù)據(jù)和 itemView 綁定。這里雖然反過(guò)來(lái)將 Adapter(Presenter) 傳入 List(ArrayObjectAdapter) 里,但其實(shí)作用也差不多,也是將兩者關(guān)聯(lián)起來(lái)。只是多了一個(gè)步驟,通過(guò)一個(gè)橋梁類 ItemBridgeAdapter 來(lái)將 ArrayObjectAdapter 里的數(shù)據(jù)傳給 Presenter 。之后 Presenter 的工作就跟 RecyclerView.Adapter 一樣了。
前面說(shuō)了 Presenter 作用類似于 Adapter,它是個(gè)抽象類,繼承它的之類需要實(shí)現(xiàn)三個(gè)方法:onCreateViewHolder()、onBindViewHolder()、onUnbindViewHolder(),同 RecyclerView.Adapter 一樣,在 onCreateViewHolder() 里面創(chuàng)建 itemView,然后在 onBindViewHolder() 里面將數(shù)據(jù)和 itemView 綁定,比如:

最后調(diào)用 BrowerFragment 的 setAdapter() 將總的 ArrayObjectAdapter 對(duì)象設(shè)置進(jìn)去,就可以了。使用很簡(jiǎn)單,如果你第一次接觸,然后直接來(lái)看這篇,也許看不懂,建議你去看看這篇博客,或者自己去看一下 Google 官方的 Tv demo,然后再回來(lái)看,相信你理解就會(huì)跟深刻了。
思考
學(xué)會(huì)初步使用 Leanback 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Home 界面后,你會(huì)發(fā)現(xiàn),我們只需要提供每一行的數(shù)據(jù),以及每行自己 itemView 的布局和數(shù)據(jù)綁定方式即可。但這完全沒(méi)有涉及到 HorizontalGridView 和 VerticalGridView ,那么它內(nèi)部的實(shí)現(xiàn)原理又是什么呢?
如果你運(yùn)行了 Google 官方 Tv sample 或者自己利用 Leanback 實(shí)現(xiàn)了簡(jiǎn)單的 Home 界面的話,你會(huì)發(fā)現(xiàn),我們焦點(diǎn)在某個(gè) item 上時(shí),這個(gè) item 會(huì)放大,焦點(diǎn)離開又恢復(fù)正常,這個(gè) Leacback 又是怎么實(shí)現(xiàn)的呢?
如果你運(yùn)行了愛(ài)奇藝的 Tv 應(yīng)用,你會(huì)發(fā)現(xiàn),它焦點(diǎn)在移動(dòng)到邊界時(shí) item 會(huì)有抖動(dòng)的效果,這又要如何實(shí)現(xiàn)呢?
本系列梳理博客大概就是要理清上面的問(wèn)題,后兩個(gè)比較簡(jiǎn)單,看了 Leanback 的源碼,已基本明白。所以難啃的點(diǎn)還是在于 Home 界面的 ui 實(shí)現(xiàn)原理,目前只能大體上明白每一行是一個(gè) HorizontalGridView,上下滑動(dòng)是由什么實(shí)現(xiàn)還沒(méi)啃透。下一篇等啃得差不多了,再來(lái)梳理一下。

最近剛開通了公眾號(hào),想激勵(lì)自己堅(jiān)持寫作下去,初期主要分享原創(chuàng)的Android或Android-Tv方面的小知識(shí),感興趣的可以點(diǎn)一波關(guān)注,謝謝支持~~