1. 程式人生 > >TabLayout和RecyclerView結合,點選TabLayout會切換到對應的RecyclerView位置,滾動RecyclerView時TabLayout會跟著切換到對應位置。

TabLayout和RecyclerView結合,點選TabLayout會切換到對應的RecyclerView位置,滾動RecyclerView時TabLayout會跟著切換到對應位置。

一、效果圖

 

二、實現原理

原理圖

1、頁面佈局從上到下為:頂部的“title”->title下面隱藏的tablayout(mainTab)->最底部的recycle人view,其中recycleview包含 1)自己的頭部、2)頭部下面的tablayout(tvTab) 、3)item。

2、計算mainTab在螢幕中的座標位置,計算滑動過程中rv中的tab在螢幕中的位置,使當rv中tab從下到上滑動到頁面title底部的時候使mainTab可見,使當rv中的tab從上到下滑出title底部時候使mainTab隱藏。

3、頁面中的tab代表屬性值和rv中的item使對應的,rv滑動過程中獲取頁面中可見的第一個item的屬性值,然後和兩個tab進行匹配,當可見的第一個item的屬性值發生變化時候切換tab到對應的一個屬性值的tab。

4、當點選mainTab或者rv中的tab時候,獲取點選的tab屬性值,找到含有此屬性值最靠前得rv中對應的一個item,然後是rv滑動到對應的位置即可。

三、實現程式碼

1、頁面佈局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/ll_home_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@color/colorPrimary"
            android:gravity="center"
            android:text="標題" />

        <View
            android:id="@+id/view_home"
            android:layout_width="match_parent"
            android:layout_height="0.1dp"
            android:background="#515151">
        </View>

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ll_home_title">
    </android.support.v7.widget.RecyclerView>

    <LinearLayout
        android:id="@+id/ll_main_tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ll_home_title"
        android:background="@color/white"
        android:orientation="vertical"
        android:visibility="invisible">

        <android.support.design.widget.TabLayout xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/tl_home"
            style="@style/TabLayoutStyle"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:background="@color/white"
            app:tabMode="scrollable">
        </android.support.design.widget.TabLayout>

        <include layout="@layout/view_divide" />

    </LinearLayout>

</RelativeLayout>

二、計算rv中的tablayout在螢幕中的位置,和頁面中的tablayout的螢幕中的位置

    //獲取頁面標題mLlHomeTitle在螢幕中的位置
    private void getTitleXY() {
        mLlHomeTitle.getLocationOnScreen(mLocationTitle);
        titleX = mLocationTitle[0];
        titleY = mLocationTitle[1];
    }

    //獲取RecyclerView中的TabLayout在螢幕中的位置
    private void getRvTabXY() {
        if (mHolderTabLayout != null) {
            mHolderTabLayout.mLlTlHome.getLocationOnScreen(mLocationRvTab);
            rvTabX = mLocationRvTab[0];
            rvTabY = mLocationRvTab[1];
        }
    }

3、監聽rv的滑動過程,獲取第一個可見的item屬性,然後切換其他兩個tab的位置

//recyclerview的滑動監聽
        mRvHome.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //獲取標題在螢幕中的的位置
                getTitleXY();
                //獲取RecyclerView的tablayout在螢幕中的位置
                getRvTabXY();
                int position = findFirstVisibleItem();
                //
                if (rvTabY > 0) {
                    int height = mLlHomeTitle.getHeight();
                    if (rvTabY <= titleY + height) {
                        mLlMainTablayout.setVisibility(View.VISIBLE);
                    } else {
                        mLlMainTablayout.setVisibility(View.INVISIBLE);
                    }
                } else {
                    if (position >= RV_HEADER_COUNT - 1) {
                        mLlMainTablayout.setVisibility(View.VISIBLE);
                    } else if (position <= RV_HEADER_COUNT - 2) {
                        mLlMainTablayout.setVisibility(View.INVISIBLE);
                    }
                }

                //這個很重要,如果true(true代表點選了頁面中的tablayout,這裡不需要再給頁面中的tablaout做改變)
                if (stopScroll) {
                    stopScroll = false;
                    return;
                }

                //根據第一個可見的item的屬性,來設定頁面中的tablayout切換到哪個tab
                if (position >= RV_HEADER_COUNT) {
                    RvData bean = mRvDatas.get(position - RV_HEADER_COUNT);
                    String shortName = bean.getParentcategory().getName();
                    int selectedTabPosition = mTlMain.getSelectedTabPosition();
                    String tabText = (String) mTlMain.getTabAt(selectedTabPosition).getText();
                    if (!shortName.equals(tabText)) {
                        for (int i = 0; i < mParentCategoryList.size(); i++) {
                            String name = mParentCategoryList.get(i).getName();
                            if (shortName.equals(name)) {
                                stopChange = true;
                                mTlMain.getTabAt(i).select();
                                break;
                            }
                        }
                    }
                }
            }
        });

4、監聽頁面中的tablayout和rv中的tablayout,如果點選了tablayout,那麼rv會滾動到對應的item位置

 //兩次監聽會有異常,新增監聽前先刪除之前的監聽
        mHolderTabLayout.mTlHome.removeOnTabSelectedListener(holderListener);
        mHolderTabLayout.mTlHome.addOnTabSelectedListener(holderListener);

        mTlMain.removeOnTabSelectedListener(mainTabListener);
        mTlMain.addOnTabSelectedListener(mainTabListener);
 //recyclerview中的tablayout監聽
    private TabLayout.OnTabSelectedListener holderListener = new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            int position = tab.getPosition();
            mTlMain.getTabAt(position).select();
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {

        }
    };

    //頁面中的tablayout的監聽
    private TabLayout.OnTabSelectedListener mainTabListener = new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            //當頁面中的tablayout被選中時
            //獲取現在的tab選中位置
            int position = tab.getPosition();
            //使RecyclerView中的tab也切換到相同的一個位置
            mHolderTabLayout.mTlHome.getTabAt(position).select();
            //如果當前tab的位置不是第一個,那麼
            if (position != 0) {
                mLlMainTablayout.setVisibility(View.VISIBLE);
            }

            //這句很關鍵,如果值為不能改變那麼,不執行
            if (stopChange) {
                stopChange = false;
                return;
            }

            //滾動到RcyclerView對應的位置
            String text = (String) mTlMain.getTabAt(position).getText();
            for (int i = 0; i < mRvDatas.size(); i++) {
                RvData bean = mRvDatas.get(i);
                if (text.equals(bean.getParentcategory().getName())) {
                    stopScroll = true;
                    mStaggeredGridLayoutManager.scrollToPositionWithOffset
                            (RV_HEADER_COUNT + i, mLlMainTablayout.getHeight());
                    break;
                }
            }
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {

        }
    };

備註:

具體實現程式碼我放在了github上 https://github.com/hnsycsxhzcsh/TabLayoutRV如果我的部落格對你有幫助的話,歡迎進入github後點擊右上角star謝謝支援!