RecyclerView實(shí)現(xiàn)瀑布流的各種坑

RecyclerView 實(shí)現(xiàn)瀑布流,關(guān)鍵是用StaggeredGridLayoutManager這個(gè)類癣籽。原以為很簡(jiǎn)單敬辣,用了之后才發(fā)現(xiàn)有很多的問題。

  • item亂跳
  • 滑動(dòng)時(shí)有空白出現(xiàn)
  • 如果item高度不固定得時(shí)候陋气,item內(nèi)容不變的時(shí)候,可能出現(xiàn)同一個(gè)item高度可能會(huì)出現(xiàn)不同的值

1. item亂跳問題

StaggeredGridLayoutManager設(shè)置空隙處理方式為 不處理引润。

setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE)

2.滑動(dòng)空白的問題

設(shè)置了StaggeredGridLayoutManager不處理空白之后巩趁,發(fā)現(xiàn)反復(fù)滑動(dòng)列表時(shí),頂部item上邊會(huì)出現(xiàn)空白淳附。網(wǎng)絡(luò)很多都是講 監(jiān)聽onScrollListener议慰,然后調(diào)用

invalidateSpanAssignments();

這個(gè)方法會(huì)重繪視圖,在scroll中調(diào)用會(huì)顯得非常頻繁奴曙,然后引起界面卡頓别凹,滑動(dòng)不流暢等問題。

本人優(yōu)化了一下洽糟,在OnScrollStateChange方法中炉菲,但列表處于SCROLL_STATE_IDLE的時(shí)候才去調(diào)用這個(gè)方法,感覺卡頓方面好很多坤溃,但是偶爾還是會(huì)出現(xiàn)頂部空白的現(xiàn)象拍霜。所以這個(gè)不能從根本上解決問題,充其量算是一種彌補(bǔ)之法薪介。

其實(shí)產(chǎn)生這個(gè)問題的根本原因在于Item的高度祠饺,尤其是高度設(shè)置為 wrap_content這種不固定的狀態(tài)。

有很多人包括網(wǎng)上都說(shuō)用map保存item的高度汁政,尤其是當(dāng)圖片瀑布流不知道圖片大小的時(shí)候道偷,第一次保存起來(lái),后面就直接從map里取值然后設(shè)置對(duì)應(yīng)控件的高度烂完。本人嘗試之后试疙,發(fā)現(xiàn)表面上看起來(lái)好像能解決問題,但是StaggeredGridLayoutManager布局跟其他的布局有點(diǎn)不一樣的地方就是 橫向的 item對(duì)應(yīng)的position不確定抠蚣,并不是像GridLayout那種從上到下祝旷,從左至右,position依次遞增。假如列表為2列怀跛,那么有可能第二行的左邊的position是2距贷,右邊是3。當(dāng)你反復(fù)滑動(dòng)幾次之后吻谋,其實(shí)就是notiftyDataChanged幾次之后忠蝗,有可能會(huì)發(fā)現(xiàn)第二行的左邊是3,右邊是2漓拾。所以保存高度這種方式也不是很靠譜阁最。

折騰了兩天之后,萬(wàn)般無(wú)賴之下骇两,發(fā)現(xiàn)只有從接口傳回的圖片數(shù)據(jù)帶上原始寬高速种,才能完美解決問題。

在已經(jīng)圖片高度的情況下低千,一切都好辦了配阵,根據(jù)屏幕寬度計(jì)算出固定的item寬度,然后對(duì)原始圖片進(jìn)行等比縮放高度示血,然后在onBindViewHolder中設(shè)置動(dòng)態(tài)設(shè)置ImageView 的高度就好了棋傍,這時(shí)候也不用map保存什么,也不需要調(diào)用invalidateSpanAssignments方法去重繪难审,因?yàn)橐呀?jīng)不會(huì)出現(xiàn)空白了瘫拣。

3.RecyclerView設(shè)置item間隔問題

剛才已經(jīng)提到,StaggeredGridLayoutManager不能根據(jù)item 的 position來(lái)判斷一個(gè)item是靠在左邊還是右邊剔宪。所以之間定義的SpaceItemDecoration不能用了拂铡,現(xiàn)在的解決辦法是 定義一個(gè)簡(jiǎn)單的SpaceItemDecoration,代碼如下:

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int space;
    private boolean includeEdge;


    public SpaceItemDecoration(int spanCount, int space) {
        this.spanCount = spanCount;
        this.space = space;

    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        outRect.left = space;
        outRect.right = space;
        if(position!=0 && position!=1){
            outRect.top = 2*space;
        }else{
            outRect.top = space;
        }


    }
}

這樣會(huì)發(fā)現(xiàn)兩列中間的間隔是 邊緣的兩倍葱绒。我的解決辦法是 給RecyclerView設(shè)置一定的padding,讓視圖看起來(lái)斗锭,四周地淀,中間 的間隔看起來(lái)都一樣大。相當(dāng)于SpaceItemDecoration岖是,不夠帮毁,還需RecyclerView補(bǔ)一刀。

當(dāng)然網(wǎng)上也有人用變量把Item是左邊還是右邊這種數(shù)據(jù)存起來(lái)豺撑,我覺的有點(diǎn)麻煩烈疚,而且第一次布局怎么辦〈辖危或許還有更好更完美的辦法等著我們?nèi)グl(fā)現(xiàn)爷肝。

4.上拉加載問題

因?yàn)镾taggeredGridLayoutManager 布局item 的position特殊性,就連findLastVisibleItemPositions方法的參數(shù)和返回值都不一樣,這個(gè)是返回一個(gè)position 數(shù)組灯抛。廢話不多說(shuō)金赦,本人自定義了一個(gè)StaggerRecyclerView專門針對(duì)StaggeredGridLayoutManager布局。代碼如下:

public class StaggerRecyclerView extends RecyclerView {

    private OnLoadMoreListener onLoadMoreListener;
    private boolean isLoadingMore = false;
    private static final int TOLAST = 6;

    public StaggerRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                StaggeredGridLayoutManager layoutManager = null ;
                if(recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager){
                    layoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
                }else{
                    return;
                }
                int[] positions = null;
                int[] into = layoutManager.findLastCompletelyVisibleItemPositions(positions);
                int lastPositon = Math.max(into[0],into[1]);
                for(int i = 0;i<into.length;i++){
                    Log.d("home","lastPositon ="+lastPositon +" | itemcount ="+layoutManager.getItemCount()+" | dx = "+dx+" | dy = "+dy);
                }

                if(!isLoadingMore && dy>0 && layoutManager.getItemCount()-lastPositon<=TOLAST){
                    //load more
                    isLoadingMore = true;
                    if(onLoadMoreListener!=null){
                        onLoadMoreListener.onLoadMore();
                    }

                }
            }
        });
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        this.onLoadMoreListener = onLoadMoreListener;
    }

    public void setLoadingMoreComplete(){
        isLoadingMore = false;
    }

    public  interface OnLoadMoreListener{
        void onLoadMore();
    }

    
}

其中 TOLAST是我定義的一個(gè)常亮对嚼,主要是決定什么時(shí)候開始加載夹抗,數(shù)字越大越提前加載,它表示提前幾個(gè)item去加載纵竖。相對(duì)于最后一個(gè)而言漠烧。往往當(dāng)我們上拉的時(shí)候,如果等到最后一個(gè)item可見的時(shí)候才去加載靡砌,可能會(huì)因?yàn)榧虞d需要時(shí)間沽甥,造成短暫的停留,體驗(yàn)不好乏奥。瀑布流嘛摆舟,最好讓用戶感知不到你的加載動(dòng)作,讓他能一直順暢的滑下去邓了。

總結(jié)一點(diǎn):實(shí)現(xiàn)瀑布流最關(guān)鍵的就是高度問題恨诱,完美的解決方案就是傳回圖片的時(shí)候順便把高度也傳回來(lái)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骗炉,一起剝皮案震驚了整個(gè)濱河市照宝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌句葵,老刑警劉巖厕鹃,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乍丈,居然都是意外死亡剂碴,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門轻专,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)忆矛,“玉大人,你說(shuō)我怎么就攤上這事请垛〈哐担” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵宗收,是天一觀的道長(zhǎng)漫拭。 經(jīng)常有香客問我,道長(zhǎng)混稽,這世上最難降的妖魔是什么采驻? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任审胚,我火速辦了婚禮,結(jié)果婚禮上挑宠,老公的妹妹穿的比我還像新娘菲盾。我一直安慰自己,他們只是感情好各淀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布懒鉴。 她就那樣靜靜地躺著,像睡著了一般碎浇。 火紅的嫁衣襯著肌膚如雪临谱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天奴璃,我揣著相機(jī)與錄音悉默,去河邊找鬼。 笑死苟穆,一個(gè)胖子當(dāng)著我的面吹牛抄课,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雳旅,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼跟磨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了攒盈?” 一聲冷哼從身側(cè)響起抵拘,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎型豁,沒想到半個(gè)月后僵蛛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迎变,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年充尉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氏豌。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喉酌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泵喘,到底是詐尸還是另有隱情,我是刑警寧澤般妙,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布纪铺,位于F島的核電站,受9級(jí)特大地震影響碟渺,放射性物質(zhì)發(fā)生泄漏鲜锚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芜繁。 院中可真熱鬧旺隙,春花似錦、人聲如沸骏令。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)榔袋。三九已至周拐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凰兑,已是汗流浹背妥粟。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吏够,地道東北人勾给。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锅知,于是被迫代替她去往敵國(guó)和親播急。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容