TabLayout和RecyclerView结合,点击TabLayout会切换到对应的RecyclerView位置,滚动RecyclerView时TabLayout会跟着切换到对应位置。

小编 2026-06-22 阅读:1042 评论:0
一、效果图   二、实现原理 1、页面布局从上到下为:顶部的“title”->title下面隐藏的tablayout(mainTab)->最底部的recycle人view,其中recy...

一、效果图

 

二、实现原理

\"原理图\"

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

 

 

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表