不嵌套RecyclerViewH镧琛!!實現有HeaderView的GridLayoutManager

序:前邊我因為項目需要擼了一下RecyclerView GridLayoutManager item設置萬能分隔線弥雹,感覺還是實用的吧垃帅,閱讀量也水漲船高,令人欣喜剪勿,也滿足了內心的小九九~~~ ??

至于這篇文章呢贸诚,是在上一篇的基礎上做加法,增加了HeadView的顯示窗宦。所以至于Item間距啥的算法赦颇,原理之類的這里就不再講解了。沒看過上一篇文章的親們赴涵,直接先去擼一把~

下面先貼個圖:


圖1.1

看到這個圖大家第一想到的做法是什么媒怯?

讓我們猜猜看:是不是一個RecyclerView(LinearLayoutManager)嵌套另一個RecyclerView(GridLayoutManager)?

嗯!我們一般都是這么做的髓窜,也沒什么不妥扇苞。

但是這里呢,我們換個角度寄纵,換個思維鳖敷,嘗試用給一個RecyclerView給它解決了~,年輕就是要燥??

照舊~ 無圖無真相??


圖1.2

圖1.3

證明確實只用了一個RecyclerView

一程拭、首先定踱,我們要對我們需要顯示的Item進行ViewType區(qū)分

    @Override
    public int getItemViewType(int position) {
        if(listData != null)
            return listData.get(position).getViewType();
        return super.getItemViewType(position);
    }

大家都看得懂哈~ 略...

二、我們要對GridLayoutManager恃鞋,做定制以用一行顯示HeaderView

final GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                int itemViewType = subAdapter.getItemViewType(position);
                if(itemViewType == Constants.PENDING_UPLOAD_SUB_VIEW_TYPE_HEADER)
                    return gridLayoutManager.getSpanCount();
                else
                    return 1;
            }
        });

這里實際上就是獲取Item的ViewType崖媚,如果是HeadView的Type就將GridLayoutManger的spanCount亦歉,變成一行。
spanSize 是說用多少個Item空間來顯示這個View(比如說可以用2個Item位置顯示該View畅哑,也可以3個等最大不超過設置的SpanCount)肴楷,我們這里是獲取spanCount,也就是3個荠呐,相當于一行赛蔫。

三、定制適合多個ViewType的ItemDecoration

其實泥张,使用一個RecyclerView來做圖1.1的效果呵恢,最重要的是要定制適合的ItemDecoration,前面文章詳解了GridLayout Item之間平均間距的原理和實現方法圾结。這里就不多說了瑰剃。

為了實現HeadView和子Item同在一個RecyclerView,并且能正確的設置他們之間的間距筝野,看起來還是挺繁瑣的,我們來試試看

3.1 首先我們要在自定義的ItemDecoration中粤剧,區(qū)分HeadView和subItem
 int spanCount = getSpanCount(parent);
 int spanSize = getSpanSize(itemPosition,parent);
 if(spanSize == spanCount){//這是有HeaderView 的情況
    ...        
 }else {//類似HeaderView 下的子item
    ...
 }

這里我們可以通過獲取GridLayoutManager的SpanCount和item的SpanSize歇竟,如果這兩者相等就說明是HeadView Item,因為我們之前在設置GridLayoutManager spansize的時候設置為gridLayoutManager.getSpanCount()抵恋。

3.2 通過上一步我們能夠區(qū)分HeadView和subItem焕议,但是仍然有個問題是:我們如何能知道每個Item的相對Position?

什么意思呢弧关?

1盅安、比如說我們Item的絕對position,是按照順序排列的世囊,0别瞭、1、2株憾、3蝙寨、4....等等
(實際上就是上一篇《RecyclerView GridLayoutManager item設置萬能分隔線》中使用到的position)

2、而我所說的Item的相對position嗤瞎,有點難解釋
先貼個上個文章的公式
第一個Item:L0=sW R0=eW-sW
第二個Item:L1=dW-R0=dW-eW+sW R1=eW-L1=2eW-dW-sW
第三個Item:L2=dW-R1=2(dW-eW)+sW R2=eW-L2=3eW-2dW-sW
所以根據以上可以得出
Ln = (position % spanCount) * (dW-eW) + sW
Rn = eW-Ln

這里可看出我們要獲取Ln = (position % spanCount) * (dW-eW) + sW中的position墙歪,而這里的這個position就不是上篇文章那個絕對Position了。

對于HeadView的left贝奇、top虹菲、right、bottom都是要設置的掉瞳,而對每個HeadView下面所屬的subItem設置left毕源、top髓帽、right、bottom就比較難了脑豹,因為如果按照《RecyclerView GridLayoutManager item設置萬能分隔線》中直接用絕對position進行計算的話郑藏,界面就亂了。

下面上一個圖:


圖1.4

在上圖中
區(qū)域一/區(qū)域二:代表了一個區(qū)塊HeadView+subItems瘩欺,而我在subItem上都標了0必盖、1、2俱饿、3...等歌粥。這些標記的數字就代表相對position,而他們本身絕對position這是他們本身實際的position:可能是1拍埠、2失驶、3、5枣购、6嬉探、7、8這樣棉圈。

而區(qū)域二中圖標0的Item實際position是多少呢涩堤? 是5! 那我們如何得到其相對position為0分瘾?那我們就需要用絕對position 減去 包含其headView之上的Item數量胎围。相當于5-5=0。 然后其后面Item的相對position 也是6-5=1德召、7-5=2白魂、8-5=3(圖上標4的給標錯了??)

那這樣看就只有相對position才能套用Ln = (position % spanCount) * (dW-eW) + sW這個公式了。

劃重點:subItem的相對position就是相對于包括他的HeadView Item以及上面 所有的Item上岗。

3.3 我們怎么獲取subItem的相對position

通過3.1福荸,我們能區(qū)分HeadView和subItem了。這點很重要

3.3.1 首先我們先定義兩個HashMap用于存儲position信息
/**
     * 意思是存儲每一個個HeadView 的之前所有Item包括自己的數量
     */
    LinkedHashMap<Integer,Integer> headPositionTotalCountMap = new LinkedHashMap<>();
    /**
     * 每一個子Item(非HeadView),存儲自己對應的headView的Item數量液茎,
     * 主要用于取余計算時逞姿,位置換算
     */
    LinkedHashMap<Integer,Integer> subItemPositionCountMap = new LinkedHashMap<>();

1、headPositionTotalCountMap:用于存儲在它之前的并包括自己的item數量
2捆等、subItemPositionCountMap: 對應于每個subItem存儲用于計算自己相對position的Items數量(每個HeadView下的subItem滞造,相對Items數量是相等的)

3.3.2 存儲用于計算相對position的items total count
if(spanSize == spanCount){//這是有HeaderView 的情況
    ...
    //如果HeadView Item沒有保存count信息,則將它之前包括自身的count栋烤,記錄      
    //到以其絕對position為Key的Map中
    if(!headPositionTotalCountMap.containsKey(itemPosition)) {
       headPositionTotalCountMap.put(itemPosition,itemPosition+1);
    }
 }else {//類似HeaderView 下的子item
    //如果subItem沒有保存count信息谒养,則將它HeadView記錄的Count取出,記錄      
    //到以其絕對position為Key的Map中
    if(!subItemPositionCountMap.containsKey(itemPosition)) {
       //找到headPostionTotalCountMap中最近的entry,獲取其value 
       int headViewTotalCount = headPositionTotalCountMap.size() == 0 ? 0 : getMapTail(headPositionTotalCountMap).getValue();
       subItemPositionCountMap.put(itemPosition, headViewTotalCount);
    }
    ...
    //通過item自身記錄的相對items count买窟,計算出相對position“(itemPosition-subItemPositionCountMap.get(itemPosition))”丰泊,套入公式
    left = (itemPosition-subItemPositionCountMap.get(itemPosition)) % spanCount * (dividerItemWidth - eachItemWidth) + spaceWidth;
    right = eachItemWidth - left;
    bottom = 0;
    top = mDividerWidth;
 }

 outRect.set(left, top, right, bottom);

代碼中注釋解釋了一波,這里大家就看看始绍,理解一下~

3.4 畫出每個區(qū)域之間的虛線

圖1.5
    //繪制不同HeadView之間虛線分割線
    private void draw(Canvas canvas, RecyclerView parent) {
        int width = mContext.getResources().getDisplayMetrics().widthPixels > mContext.getResources().getDisplayMetrics().heightPixels
                ? mContext.getResources().getDisplayMetrics().heightPixels : mContext.getResources().getDisplayMetrics().widthPixels;
        int spanCount = getSpanCount(parent);

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            int itemPosition = ((RecyclerView.LayoutParams) child.getLayoutParams()).getViewLayoutPosition();
            int spanSize = getSpanSize(itemPosition,parent);

            if(spanCount == spanSize && itemPosition != 0){
                mPath.reset();
                mPath.moveTo(child.getLeft()-5,child.getTop()-mDividerWidth);
                mPath.lineTo(width-mDividerWidth+5,child.getTop()-mDividerWidth);
                canvas.drawPath(mPath,mPaint);
            }
        }
    }

畫虛線就比較簡單了幾大件:Path瞳购、Paint、Canvas配置好就行亏推,然后獲取每個headView的top学赛、left、屏幕寬度就可以畫出虛線吞杭,這里就不多說了盏浇。

好了,到這里《不嵌套RecyclerView芽狗,實現有HeaderView的GridLayoutManager》就講完了 绢掰,它沒有嵌套RecyclerView來實現文中UI,并且能很好的平分間隔童擎,不會使item位置錯亂滴劲。另外,可能文中一些東西沒講清楚柔昼,如若有任何問題哑芹,都可以留言,我看到后會第一時間回復捕透!See you next article~

我已將GridDividerItemDecoration,上傳到GitHub:https://github.com/haozi5460/GridDividerMoreTypeItemDecoration

申明:禁用于商業(yè)用途碴萧,如若轉載乙嘀,請附帶原文鏈接。http://www.reibang.com/p/ea4d9843dada 蟹蟹(#.#)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末破喻,一起剝皮案震驚了整個濱河市虎谢,隨后出現的幾起案子,更是在濱河造成了極大的恐慌曹质,老刑警劉巖婴噩,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異羽德,居然都是意外死亡几莽,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門宅静,熙熙樓的掌柜王于貴愁眉苦臉地迎上來章蚣,“玉大人,你說我怎么就攤上這事姨夹∠舜梗” “怎么了矾策?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長峭沦。 經常有香客問我贾虽,道長,這世上最難降的妖魔是什么吼鱼? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任蓬豁,我火速辦了婚禮,結果婚禮上蛉抓,老公的妹妹穿的比我還像新娘庆尘。我一直安慰自己,他們只是感情好巷送,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布驶忌。 她就那樣靜靜地躺著,像睡著了一般笑跛。 火紅的嫁衣襯著肌膚如雪付魔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天飞蹂,我揣著相機與錄音几苍,去河邊找鬼。 笑死陈哑,一個胖子當著我的面吹牛妻坝,可吹牛的內容都是我干的。 我是一名探鬼主播惊窖,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼刽宪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了界酒?” 一聲冷哼從身側響起圣拄,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毁欣,沒想到半個月后庇谆,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡凭疮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年饭耳,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哭尝。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡哥攘,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情逝淹,我是刑警寧澤耕姊,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站栅葡,受9級特大地震影響茉兰,放射性物質發(fā)生泄漏。R本人自食惡果不足惜欣簇,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一规脸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熊咽,春花似錦莫鸭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衫仑,卻和暖如春梨与,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背文狱。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工粥鞋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瞄崇。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓呻粹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苏研。 傳聞我的和親對象是個殘疾皇子尚猿,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容