转载请标明出处:https://blog.youkuaiyun.com/m0_38074457/article/details/85120375,本文出自【陈少华的博客】
一、效果图
二、实现原理
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支持!