1. 程式人生 > >Recycle獲取第一個可見條目(包括瀑布流)位置以及getChildAt(position)

Recycle獲取第一個可見條目(包括瀑布流)位置以及getChildAt(position)

前言

RecyclerView跟隨Android5.0釋出已久了,幾乎從RecyclerView問世之初,我就拋棄ListView和GridView轉投RecyclerView的懷抱了!沒啥原因,只因為方便、省心。如它名字所示Recycler+View,代表著它擁有良好的回收機制以及良好的複用能力,而且強制使用了ViewHolder所以效能不用擔心。當我們想要新增增刪動畫時,只需要通過ItemAnimator,一條語句就能解決。ListView?GridView?瀑布流?一條語句快速切換。叫我怎能不愛。然而。。。谷歌這次沒賦予它點選事件,這意味著需要自己寫點選事件,不過也不難,通過adapter提供回撥就行,事件監聽器從recyclerview換成了Adapter而已。一切都那麼美好,直到今天下午。。。

問題描述

最近在做一個小專案,在點選item時更新item的UI,這個一般來講就是獲取到View然後在繫結控制元件,做相應的修改就行,也就一、兩條語句的事嘛。好了怎麼獲取對應的View呢,根據ListView的經驗,恩,recycleview.getChildAt(position)就行了吧!剛開始只有4條資料的時候確實就這樣就行了,當資料多了,螢幕顯示不完,拉下去點選之前未顯示的就Crash了。

解決方案

前言說了RecyclerView有良好的回收機制,所以只加載螢幕顯示的View,未顯示部分將回收。由於getChildAt()這個方法只能get到螢幕顯示的部分,也就是說:假如螢幕上只能顯示6個View,當往下滑動到第7、8個View的時候,他們的position雖然還是6,7但是由於getChildAt()

只能get到螢幕上顯示的View,所以它實際的position其實是4、5。想要get到第7個View不能用getChildAt(6)而要用getChildAt(4).其實這問題之前在ListView中也出現過,不過只需要用當前的position減去螢幕顯示的第一個View的position(getFirstVisiblePosition())就行。然而recyclerview中並沒有獲取第一個View的方法。好了百度、谷歌找了一大圈,最後在stackoverflow找到了相關描述,據說只需要這樣((LinearLayoutManager)LayoutManager).findFirstVisibleItemPosition()
或者這樣((GridLayoutManager)LayoutManager).findFirstVisibleItemPosition()就行了。然而。。。我用的瀑布流StaggeredGridLayoutManager。StaggeredGridLayoutManager中的這個方法需要傳入一個int[],然後懵逼,然後又是一大圈的趴文,然後依然是在stackoverflow中找到了相關描述,據說這是谷歌的bug,只能繞一繞,結果真的只是繞一繞,廢話太多了直接上程式碼吧。。。

int[] firstVisibleItems = null;

firstVisibleItems=  ((StaggeredGridLayoutManager)recycleview.getLayoutManager()).findFirstVisibleItemPositions(firstVisibleItems);

真的是很繞對吧?最終陣列中第1個元素就是所要的第一個position,下標0.所以獲取當前view的真實Position就是position - firstVisibleItems[0]。
好了此貼終結。。。

後記

真的強烈安利stackoverflow,幾乎所有神奇的問題都可以從這趴到解決方案,雖然全英,不過技術問答看懂不難。