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谢谢支持!

猜你喜欢

转载自blog.csdn.net/m0_38074457/article/details/85120375