TabLayout和RecyclerView結合,點選TabLayout會切換到對應的RecyclerView位置,滾動RecyclerView時TabLayout會跟著切換到對應位置。
阿新 • • 發佈:2018-12-23
一、效果圖
二、實現原理
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謝謝支援!