TabLayout+ViewPager2联动
以前,viewpager+tablayout联动,只需要以下两行代码就解决,
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));mTabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
类似的,官方也为了我们提示了tablayout+viewpager2的联动工具类:TabLayoutMediator
使用的时候只需要以下几行代码,就实现了tablayout+viewpager2联动
new TabLayoutMediator(tabLayout, viewPager2, true,new TabLayoutMediator.OnConfigureTabCallback() {@Overridepublic void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {//这里需要根据position修改tab的样式和文字等tab.setText("fragment"+position);}}).attach();
注:material1.1.0之前,material包是不包含TabLayoutMediator的,想使用需要复制TabLayoutMediator源码,源码在下面!!
示例:
xml代码:简单的界面,顶部tablayout,底部viewpager2
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".Main2Activity"><com.google.android.material.tabs.TabLayoutandroid:id="@+id/tablayout"android:layout_width="match_parent"android:layout_height="wrap_content"app:tabIndicatorColor="@color/colorPrimary"app:tabTextColor="@color/colorAccent"app:tabSelectedTextColor="@color/colorPrimary"app:tabIndicatorFullWidth="false"app:tabMode="scrollable"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><androidx.viewpager2.widget.ViewPager2android:id="@+id/viewpager2"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/tablayout" /></androidx.constraintlayout.widget.ConstraintLayout>
activity代码:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);viewPager2 = findViewById(R.id.viewpager2);tabLayout = findViewById(R.id.tablayout);viewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);List<Fragment> fragments = new ArrayList<>();for (int i = 0; i < 20; i++) {fragments.add(BlankFragment.newInstance());}viewPager2.setAdapter(new FragmentStateAdapter(this) {@NonNull@Overridepublic Fragment createFragment(int position) {Fragment fragment = fragments.get(position);return fragment;}@Overridepublic int getItemCount() {return fragments.size();}});viewPager2.setOffscreenPageLimit(3);new TabLayoutMediator(tabLayout, viewPager2, true,new TabLayoutMediator.OnConfigureTabCallback() {@Overridepublic void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {//这里需要根据position修改tab的样式和文字等tab.setText("fragment"+position);}}).attach();//最后一定要attach()}
TabLayoutMediator源码:直接拷贝到你的项目里就能用
@RestrictTo(LIBRARY_GROUP)
public final class TabLayoutMediator {private final @NonNullTabLayout mTabLayout;private final @NonNullViewPager2 mViewPager;private final boolean mAutoRefresh;private final OnConfigureTabCallback mOnConfigureTabCallback;private RecyclerView.Adapter mAdapter;private boolean mAttached;private TabLayoutOnPageChangeCallback mOnPageChangeCallback;private TabLayout.OnTabSelectedListener mOnTabSelectedListener;private RecyclerView.AdapterDataObserver mPagerAdapterObserver;/*** A callback interface that must be implemented to set the text and styling of newly created* tabs.*/public interface OnConfigureTabCallback {/*** Called to configure the tab for the page at the specified position. Typically calls** @param tab The Tab which should be configured to represent the title of the item at the* given position in the data set.* @param position The position of the item within the adapter's data set.*/void onConfigureTab(@NonNull TabLayout.Tab tab, int position);}/*** Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. It will* update the tabs automatically when the data set of the view pager's adapter changes. The link* will be established after {@link #attach()} is called.** @param tabLayout The tab bar to link* @param viewPager The view pager to link*/public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,@NonNull OnConfigureTabCallback onConfigureTabCallback) {this(tabLayout, viewPager, true, onConfigureTabCallback);}/*** Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. If {@code* autoRefresh} is true, it will update the tabs automatically when the data set of the view* pager's adapter changes. The link will be established after {@link #attach()} is called.** @param tabLayout The tab bar to link* @param viewPager The view pager to link* @param autoRefresh If {@code true}, will recreate all tabs when the data set of the view* pager's adapter changes.*/public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,boolean autoRefresh, @NonNull OnConfigureTabCallback onConfigureTabCallback) {mTabLayout = tabLayout;mViewPager = viewPager;mAutoRefresh = autoRefresh;mOnConfigureTabCallback = onConfigureTabCallback;}/*** Link the TabLayout and the ViewPager2 together.* adapter.*/public void attach() {if (mAttached) {throw new IllegalStateException("TabLayoutMediator is already attached");}mAdapter = mViewPager.getAdapter();if (mAdapter == null) {throw new IllegalStateException("TabLayoutMediator attached before ViewPager2 has an "+ "adapter");}mAttached = true;// Add our custom OnPageChangeCallback to the ViewPagermOnPageChangeCallback = new TabLayoutOnPageChangeCallback(mTabLayout);mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);// Now we'll add a tab selected listener to set ViewPager's current itemmOnTabSelectedListener = new ViewPagerOnTabSelectedListener(mViewPager);mTabLayout.addOnTabSelectedListener(mOnTabSelectedListener);// Now we'll populate ourselves from the pager adapter, adding an observer if// autoRefresh is enabledif (mAutoRefresh) {// Register our observer on the new adaptermPagerAdapterObserver = new PagerAdapterObserver();mAdapter.registerAdapterDataObserver(mPagerAdapterObserver);}populateTabsFromPagerAdapter();// Now update the scroll position to match the ViewPager's current itemmTabLayout.setScrollPosition(mViewPager.getCurrentItem(), 0f, true);}/*** Unlink the TabLayout and the ViewPager*/public void detach() {mAdapter.unregisterAdapterDataObserver(mPagerAdapterObserver);mTabLayout.removeOnTabSelectedListener(mOnTabSelectedListener);mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);mPagerAdapterObserver = null;mOnTabSelectedListener = null;mOnPageChangeCallback = null;}@SuppressWarnings("WeakerAccess")void populateTabsFromPagerAdapter() {mTabLayout.removeAllTabs();if (mAdapter != null) {int adapterCount = mAdapter.getItemCount();for (int i = 0; i < adapterCount; i++) {TabLayout.Tab tab = mTabLayout.newTab();mOnConfigureTabCallback.onConfigureTab(tab, i);mTabLayout.addTab(tab, false);}// Make sure we reflect the currently set ViewPager itemif (adapterCount > 0) {int currItem = mViewPager.getCurrentItem();if (currItem != mTabLayout.getSelectedTabPosition()) {mTabLayout.getTabAt(currItem).select();}}}}/*** A {@link ViewPager2.OnPageChangeCallback} class which contains the necessary calls back to* the provided {@link TabLayout} so that the tab position is kept in sync.** <p>This class stores the provided TabLayout weakly, meaning that you can use {@link* ViewPager2#registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback)} without removing* the callback and not cause a leak.*/private static class TabLayoutOnPageChangeCallback extends ViewPager2.OnPageChangeCallback {private final WeakReference<TabLayout> mTabLayoutRef;private int mPreviousScrollState;private int mScrollState;TabLayoutOnPageChangeCallback(TabLayout tabLayout) {mTabLayoutRef = new WeakReference<>(tabLayout);reset();}@Overridepublic void onPageScrollStateChanged(final int state) {mPreviousScrollState = mScrollState;mScrollState = state;}@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {TabLayout tabLayout = mTabLayoutRef.get();if (tabLayout != null) {// Only update the text selection if we're not settling, or we are settling after// being draggedboolean updateText = mScrollState != SCROLL_STATE_SETTLING|| mPreviousScrollState == SCROLL_STATE_DRAGGING;// Update the indicator if we're not settling after being idle. This is caused// from a setCurrentItem() call and will be handled by an animation from// onPageSelected() instead.boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING&& mPreviousScrollState == SCROLL_STATE_IDLE);setScrollPosition(tabLayout, position, positionOffset, updateText, updateIndicator);}}@Overridepublic void onPageSelected(final int position) {TabLayout tabLayout = mTabLayoutRef.get();if (tabLayout != null&& tabLayout.getSelectedTabPosition() != position&& position < tabLayout.getTabCount()) {// Select the tab, only updating the indicator if we're not being dragged/settled// (since onPageScrolled will handle that).boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE|| (mScrollState == SCROLL_STATE_SETTLING&& mPreviousScrollState == SCROLL_STATE_IDLE);selectTab(tabLayout, tabLayout.getTabAt(position), updateIndicator);}}void reset() {mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;}}// region Reflective calls// Temporarily call methods TabLayout.setScrollPosition(int, float, boolean, boolean) and// TabLayout.selectTab(TabLayout.Tab, boolean) through reflection, until they have been made// public in the Material Design Components library.private static Method sSetScrollPosition;private static Method sSelectTab;private static final String SET_SCROLL_POSITION_NAME = "TabLayout.setScrollPosition(int, float,"+ " boolean, boolean)";private static final String SELECT_TAB_NAME = "TabLayout.selectTab(TabLayout.Tab, boolean)";static {try {sSetScrollPosition = TabLayout.class.getDeclaredMethod("setScrollPosition", int.class,float.class, boolean.class, boolean.class);sSetScrollPosition.setAccessible(true);sSelectTab = TabLayout.class.getDeclaredMethod("selectTab", TabLayout.Tab.class,boolean.class);sSelectTab.setAccessible(true);} catch (NoSuchMethodException e) {throw new IllegalStateException("Can't reflect into method TabLayout"+ ".setScrollPosition(int, float, boolean, boolean)");}}@SuppressWarnings("WeakerAccess")static void setScrollPosition(TabLayout tabLayout, int position, float positionOffset,boolean updateSelectedText, boolean updateIndicatorPosition) {try {if (sSetScrollPosition != null) {sSetScrollPosition.invoke(tabLayout, position, positionOffset, updateSelectedText,updateIndicatorPosition);} else {throwMethodNotFound(SET_SCROLL_POSITION_NAME);}} catch (Exception e) {throwInvokeFailed(SET_SCROLL_POSITION_NAME);}}@SuppressWarnings("WeakerAccess")static void selectTab(TabLayout tabLayout, TabLayout.Tab tab, boolean updateIndicator) {try {if (sSelectTab != null) {sSelectTab.invoke(tabLayout, tab, updateIndicator);} else {throwMethodNotFound(SELECT_TAB_NAME);}} catch (Exception e) {throwInvokeFailed(SELECT_TAB_NAME);}}private static void throwMethodNotFound(String method) {throw new IllegalStateException("Method " + method + " not found");}private static void throwInvokeFailed(String method) {throw new IllegalStateException("Couldn't invoke method " + method);}// endregion/*** A {@link TabLayout.OnTabSelectedListener} class which contains the necessary calls back to* the provided {@link ViewPager2} so that the tab position is kept in sync.*/private static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {private final ViewPager2 mViewPager;ViewPagerOnTabSelectedListener(ViewPager2 viewPager) {this.mViewPager = viewPager;}@Overridepublic void onTabSelected(TabLayout.Tab tab) {mViewPager.setCurrentItem(tab.getPosition(), true);}@Overridepublic void onTabUnselected(TabLayout.Tab tab) {// No-op}@Overridepublic void onTabReselected(TabLayout.Tab tab) {// No-op}}private class PagerAdapterObserver extends RecyclerView.AdapterDataObserver {PagerAdapterObserver() {}@Overridepublic void onChanged() {populateTabsFromPagerAdapter();}@Overridepublic void onItemRangeChanged(int positionStart, int itemCount) {populateTabsFromPagerAdapter();}@Overridepublic void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {populateTabsFromPagerAdapter();}@Overridepublic void onItemRangeInserted(int positionStart, int itemCount) {populateTabsFromPagerAdapter();}@Overridepublic void onItemRangeRemoved(int positionStart, int itemCount) {populateTabsFromPagerAdapter();}@Overridepublic void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {populateTabsFromPagerAdapter();}}
}
查看TabLayoutMediator代码,不难发现,内部也是实现了TabLayout.OnTabSelectedListener和ViewPager2.OnPageChangeCallback,参考官方的写法,我们可以写自己的tablayout和viewpager2的联动
这部分内容将在下一章讲解
TabLayout+ViewPager2联动相关推荐
- Android之TabLayout+ViewPager2+FragmentStateAdapter实现带数字变化的TAB选项
1 问题 TabLayout+ViewPager2实现带数字变化的TAB选项,然后左边滑动或者点击上面的Tab切换fragment不能刷新 2 结果爆照 3 代码实现 layer_tab_indica ...
- RecyclerView与ViewPager2
RecyclerView与ViewPager2 文章目录 RecyclerView与ViewPager2 1:RecyclerView 1.1:基本使用方法 1.1.1定制 RecyclerView ...
- android tab 切换动画,Android之ViewPager+TabLayout组合实现导航条切换效果(微信和QQ底部多标签切换)...
前言 之前在另外一篇中用Fragment和button实现了点击切换Fragment的效果,比较简陋.这次改用ViewPager+TabLayout 实现联动的效果. 实现效果 ViewPager 多 ...
- Android ViewPager2总结
文章目录 ViewPager2总结 概述 常用API ViewPager2基本使用 ViewPager2+TabLayout+Fragment 代码下载 ViewPager2总结 概述 ViewPag ...
- ViewPager2的使用
文章目录 简介 源码简单了解 改动点 常用Api 引入implementation 官方demo介绍 ViewPager2 with Views ViewPager2 with Fragments V ...
- android解决 Button 和 TabLayout 英文自动大写的问题
解决 Button 和 TabLayout 英文自动大写的问题 导言:今天在使用TabLayout + ViewPager2加载页面时发现TabLayout 标题威英文时,全部都是大写展示.为此苦恼许 ...
- 安卓知识体系搭建(持续更新)
Java基础 日期操作类 [Android]DecimalFormat简单使用 Java语言编程规范--注释规范 Java内存分配之堆.栈和常量池 Java泛型详解 深入浅出Java中的增强 for ...
- 幻樱の安卓开发学习笔记(持续更新)
安卓开发手册Java . 前言 . 本篇博客是我在开发过程中遇到的一些问题,我将这些问题记录了下来,以防踩重复的坑,希望对需要学习或者来看我踩坑的人有所帮助. . . . . 零.一些常用的依赖 1. ...
- Android 锁屏无法继续定位问题
code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:我的梦z 链接:https://www.jianshu.com/p/956cbba64c53 声明:本文已获我的 ...
最新文章
- 排序算法7---快速排序算法
- object.create()
- 骚操作!用 CPU 烤肉,这位程序员做到了
- 电脑计算机内存不够怎么办,电脑内存不足怎么办 电脑内存不足怎么解决
- 如果有人再问你 Java 的反射,把这篇文章扔给他
- 查看cp进度,使用watch
- LeetCode刷题(13)
- uniapp 拍照 或者 相册 识别身份证信息
- c语言求布尔矩阵的乘积,离散数学 关系矩阵的布尔乘法的简便方法
- linux 好书推荐
- 2022年中南大学计算机考研复试内容是什么
- java 9宫格抽奖_九宫格抽奖
- 笔记本linux如何降低功耗,细说如何降低笔记本电脑功耗
- 解析大多数WordPress用户都选择托管虚拟主机的原因
- 【FXCG】落花有意随流水,流水无意恋落花
- 视频显示设备和光栅扫描系统
- layui做折线图_flask+layui+echarts实现前端动态图展示数据效果
- [大数据概念]-- 大数据的技术生态比喻
- 【DLL动态链接库】解决自己编写的程序在别人的电脑上无法运行的问题
- php微信支付结果通知接收,浅析PHP微信支付通知的处理方式
热门文章
- HTML5 新增的结构元素——能用不代表用对了
- Rtools 环境变量设置-windows
- python多维字典_python定义多维字典
- java jdbc 批量更新_java – JDBC PreparedStatement,批量更新和生成的密钥
- 用户行为分析(如何用数据驱动增长)-读书笔记1
- php apache win7,win7配置Apache24和PHP7.2.4开发环境
- 一篇文章通透理解序列号实现原理
- Google的60款开源项目
- [Unity][blender]在blender中新建标准两足人形骨骼模型动作导入到Unity中
- Java爬虫Jsoup的使用