RecyclerView進(jìn)階(一)RecyclerView實(shí)現(xiàn)雙列表聯(lián)動(dòng)

本篇文章已授權(quán)微信公眾號(hào) hongyangAndroid (鴻洋)獨(dú)家發(fā)布

最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)分類(lèi)頁(yè)面

  • UI圖
列表聯(lián)動(dòng)效果圖

實(shí)現(xiàn)要求

  1. 左側(cè)聯(lián)動(dòng)右側(cè):
    點(diǎn)擊左側(cè)列表的某一項(xiàng)饼问,背景變色乾闰,同時(shí)右側(cè)列表中對(duì)應(yīng)的分類(lèi)滾動(dòng)到頂部
  2. 右側(cè)列表懸停:
    右側(cè)列表滑動(dòng)的時(shí)候相應(yīng)的標(biāo)題欄需要在頂部懸停
  3. 標(biāo)題欄可點(diǎn)擊
  4. 右側(cè)聯(lián)動(dòng)左側(cè):
    滾動(dòng)右側(cè)列表默刚,監(jiān)聽(tīng)滾動(dòng)的位置腺怯,左側(cè)列表需要同步選中相應(yīng)的列表
  • 效果圖
列表聯(lián)動(dòng)效果圖

對(duì)照著上面的UI要求轨奄,基本上實(shí)現(xiàn)了所有的需求裳仆,下面分享一下實(shí)現(xiàn)的思路

左側(cè)聯(lián)動(dòng)右側(cè)

兩側(cè)都是Recyclerview溉箕,一開(kāi)始以為就是調(diào)用一下Recyclerview的scrollToPostion滾動(dòng)到具體的位置就好晦墙,但是實(shí)際上并非如此,因?yàn)镽ecyclerview的滾動(dòng)方法有兩種

  • scrollToPosition(int)

但是實(shí)際上調(diào)用的時(shí)候就比較坑爹肴茄,分為兩種情況

  • 從上往下滾動(dòng)

如果是從上往下滾動(dòng)的時(shí)候晌畅,發(fā)現(xiàn)每次達(dá)不到預(yù)期的效果,只能將需要滾動(dòng)的item的顯示出來(lái)而已寡痰,并不能滾動(dòng)到頂部

  • 從下滾動(dòng)

這種情況是OK的抗楔,每次能夠達(dá)到想要的效果

  • scrollBy(int x,int y)

這個(gè)方法如果是針對(duì)LinearLayoutManager的話(huà),可以動(dòng)態(tài)計(jì)算滾動(dòng)的高度拦坠,但是針對(duì)相對(duì)復(fù)雜的布局就非常麻煩连躏,最后找到了一種解決方案:

  1. 滾動(dòng)的position小于FirstVisibleItemPosition

直接調(diào)用scrollToPosition

 mRv.smoothScrollToPosition(n);
  1. 滾動(dòng)的position介于FirstVisibleItemPosition與LastVisibleItemPosition之間

獲取需要滾動(dòng)的position距離頂部的高度,然后調(diào)用scrollBy

 int top = mRv.getChildAt(n - firstItem).getTop();
    mRv.smoothScrollBy(0, top);
  1. 滾動(dòng)的position>LastVisibleItemPosition

先調(diào)用scrollToPosition將需要滾動(dòng)的position顯示出來(lái)贞滨,在滾動(dòng)完成時(shí)進(jìn)行監(jiān)聽(tīng)入热,當(dāng)滾動(dòng)停止的時(shí)候,執(zhí)行跟2中相同的操作晓铆,達(dá)到目的

整體代碼如下

//通過(guò)滾動(dòng)的類(lèi)型來(lái)進(jìn)行相應(yīng)的滾動(dòng)
 
  private void smoothMoveToPosition(int n) {
        int firstItem = mManager.findFirstVisibleItemPosition();
        int lastItem = mManager.findLastVisibleItemPosition();
        if (n <= firstItem) {
            mRv.smoothScrollToPosition(n);
        } else if (n <= lastItem) {
            int top = mRv.getChildAt(n - firstItem).getTop();
            mRv.smoothScrollBy(0, top);
        } else {
            mRv.smoothScrollToPosition(n);
            move = true;
        }
    }

 //監(jiān)聽(tīng)第三種情況才顿,滾動(dòng)停止之后再次進(jìn)行滾動(dòng)

    private class RecyclerViewListener extends RecyclerView.OnScrollListener {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (move && newState == RecyclerView.SCROLL_STATE_IDLE) {
                move = false;
                int n = mIndex - mManager.findFirstVisibleItemPosition();
                Log.d("n---->", String.valueOf(n));
                if (0 <= n && n < mRv.getChildCount()) {
                    int top = mRv.getChildAt(n).getTop();
                    Log.d("top--->", String.valueOf(top));
                    mRv.smoothScrollBy(0, top);
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
        }
    }

右側(cè)列表懸停

之前有看過(guò)張旭童的關(guān)于利用itemDecoration來(lái)實(shí)現(xiàn)城市列表索引的博客,寫(xiě)的的確是挺好的尤蒿,唯一遺憾的是itemDecoration實(shí)現(xiàn)的頭部不支持點(diǎn)擊郑气,所以這里換了另外一種思路。

  • Sectioned實(shí)現(xiàn)方式

偽造一個(gè)頭部,給一個(gè)標(biāo)志腰池,然后加入到已有的數(shù)據(jù)集合中尾组,然后再Recyclerview的Adapter中針對(duì)此標(biāo)志返回標(biāo)題欄的布局,達(dá)到分組的目的

   for (int i = 0; i < data.length; i++) {
            SortBean titleBean = new SortBean(String.valueOf(i));
            titleBean.setTitle(true);//頭部設(shè)置為true,默認(rèn)為false
            titleBean.setTag(String.valueOf(i));
            mDatas.add(titleBean);
            for (int j = 0; j < 10; j++) {
                SortBean sortBean = new SortBean(String.valueOf(i + "行" + j + "個(gè)"));
                sortBean.setTag(String.valueOf(i));
                mDatas.add(sortBean);
            }

        }
        
  @Override
    protected int getLayoutId(int viewType) {
        return viewType == 0 ? R.layout.item_title : R.layout.item_classify_detail;
    }

    @Override
    public int getItemViewType(int position) {
        return list.get(position).isTitle() ? 0 : 1;
    }

  • 懸停的實(shí)現(xiàn)

其實(shí)這個(gè)利用了itemDecoration示弓,調(diào)用RecyclerView.ItemDecoration的onDrawOver中進(jìn)行繪制一個(gè)跟Title一模一樣的標(biāo)題欄就好了讳侨,這樣就把第一個(gè)Section覆蓋了,看起
來(lái)好像是懸停的感覺(jué)

  • 當(dāng)發(fā)現(xiàn)下一個(gè)title頂上來(lái)的時(shí)候奏属,將canvas向上平移跨跨,產(chǎn)生一種向上擠壓的動(dòng)畫(huà)效果
   if (null != tag && !tag.equals(suspensionTag)) {
               if (child.getHeight() + child.getTop() < mTitleHeight) {
                    c.save();
                    flag = true;
                    c.translate(0, child.getHeight() + child.getTop() mTitleHeight);
                }
            }
  • 繪制懸停的頭部

這里沒(méi)有一個(gè)一個(gè)控件的進(jìn)行繪制,因?yàn)閱蝹€(gè)繪制比較麻煩,所以直接繪制了整個(gè)布局勇婴,同時(shí)修改了布局中標(biāo)題欄中的內(nèi)容

 View topTitleView = mInflater.inflate(R.layout.item_title, parent, false);
        TextView tvTitle = (TextView) topTitleView.findViewById(R.id.tv_title);
        tvTitle.setText("測(cè)試數(shù)據(jù)" + tag);
        
    //進(jìn)行測(cè)量獲取MeasureSpec:toDrawWidthSpec忱嘹,toDrawHeightSpec,代碼省略
    
     //依次調(diào)用 measure,layout,draw方法耕渴,將復(fù)雜頭部顯示在屏幕上拘悦。
        topTitleView.measure(toDrawWidthSpec, toDrawHeightSpec);
        topTitleView.layout(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getPaddingLeft() + topTitleView.getMeasuredWidth(), parent.getPaddingTop() + topTitleView.getMeasuredHeight());
        topTitleView.draw(c);//Canvas默認(rèn)在視圖頂部,無(wú)需平移橱脸,直接繪制

標(biāo)題欄可點(diǎn)擊

由于是采用的布局而不是itemDecoration的實(shí)現(xiàn)础米,所以所有的標(biāo)題欄都是可以點(diǎn)擊跳轉(zhuǎn)的

右側(cè)聯(lián)動(dòng)左側(cè)

當(dāng)右側(cè)懸停的title內(nèi)容發(fā)生變化的時(shí)候,通過(guò)一個(gè)接口進(jìn)行回調(diào)左側(cè)列表即可添诉,比較簡(jiǎn)單屁桑,貼下代碼:

    if (!Objects.equals(tag, currentTag)) {
            Log.d("tag---->", String.valueOf(MainActivity.finalNumber));
            currentTag = tag;
            Integer integer = Integer.valueOf(currentTag);
            mCheckListener.check(integer, false);
        }

Demo下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市栏赴,隨后出現(xiàn)的幾起案子蘑斧,更是在濱河造成了極大的恐慌,老刑警劉巖艾帐,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盆偿,居然都是意外死亡柒爸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)事扭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捎稚,“玉大人,你說(shuō)我怎么就攤上這事求橄〗褚埃” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵罐农,是天一觀的道長(zhǎng)条霜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)涵亏,這世上最難降的妖魔是什么宰睡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮气筋,結(jié)果婚禮上拆内,老公的妹妹穿的比我還像新娘。我一直安慰自己宠默,他們只是感情好麸恍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著搀矫,像睡著了一般抹沪。 火紅的嫁衣襯著肌膚如雪刻肄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天采够,我揣著相機(jī)與錄音肄方,去河邊找鬼。 笑死蹬癌,一個(gè)胖子當(dāng)著我的面吹牛权她,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逝薪,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隅要,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了董济?” 一聲冷哼從身側(cè)響起步清,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虏肾,沒(méi)想到半個(gè)月后廓啊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡封豪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年谴轮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吹埠。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡第步,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缘琅,到底是詐尸還是另有隱情粘都,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布刷袍,位于F島的核電站翩隧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呻纹。R本人自食惡果不足惜鸽心,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望居暖。 院中可真熱鬧顽频,春花似錦、人聲如沸太闺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蟀淮,卻和暖如春最住,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怠惶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工涨缚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人策治。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓脓魏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親通惫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茂翔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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