重学Android之View——TabLayoutMediator解析

news2024/9/27 5:51:52

重学Android之View——TabLayoutMediator解析

1.前言

在使用TabLayout+ViewPager2+Fragment的时候,查询别人的使用例子,看到了

TabLayoutMediator这个类,撰写此文,仅当学习思考,本文是在引用material:1.7.0的版本基础上

2.测试效果

Tab + ViewPager2 + Fragment

tab

3.内部成员变量介绍

public final class TabLayoutMediator {
  @NonNull private final TabLayout tabLayout;
  @NonNull private final ViewPager2 viewPager;
  private final boolean autoRefresh;
  private final boolean smoothScroll;
  private final TabConfigurationStrategy tabConfigurationStrategy;
  @Nullable private RecyclerView.Adapter<?> adapter;
  private boolean attached;

  @Nullable private TabLayoutOnPageChangeCallback onPageChangeCallback;
  @Nullable private TabLayout.OnTabSelectedListener onTabSelectedListener;
  @Nullable private RecyclerView.AdapterDataObserver pagerAdapterObserver;
 ......

TabLayoutMediator类引用了tabLayout跟ViewPager2对象,另外内部定义定义了tabLayout跟Viewpager2的

监听回调类,还有adapter关于数据的监听类

4.TabLayoutOnPageChangeCallback

这个是viewPager2的监听类,主要目的是,在viewPager2发生页面变化的时候,去同步更新TabLaout的状态

,通过使用如下TabLaout的Api去更新tabLayout的状态

 tabLayout.selectTab()
 tabLayout.setScrollPosition()

并且通过如下方法,注册到viewPager的监听器中

viewPager.registerOnPageChangeCallback();

具体的ViewPager2.OnPageChangeCallback的监听类,在这里不仔细介绍

private static class TabLayoutOnPageChangeCallback extends ViewPager2.OnPageChangeCallback {
    @NonNull private final WeakReference<TabLayout> tabLayoutRef;
    private int previousScrollState;
    private int scrollState;

    TabLayoutOnPageChangeCallback(TabLayout tabLayout) {
      tabLayoutRef = new WeakReference<>(tabLayout);
      reset();
    }

    @Override
    public void onPageScrollStateChanged(final int state) {
      previousScrollState = scrollState;
      scrollState = state;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
      TabLayout tabLayout = tabLayoutRef.get();
      if (tabLayout != null) {
        // Only update the text selection if we're not settling, or we are settling after
        // being dragged
        boolean updateText =
            scrollState != SCROLL_STATE_SETTLING || previousScrollState == 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 =
            !(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE);
        tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
      }
    }

    @Override
    public void onPageSelected(final int position) {
      TabLayout tabLayout = tabLayoutRef.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 =
            scrollState == SCROLL_STATE_IDLE
                || (scrollState == SCROLL_STATE_SETTLING
                    && previousScrollState == SCROLL_STATE_IDLE);
        tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
      }
    }

    void reset() {
      previousScrollState = scrollState = SCROLL_STATE_IDLE;
    }
  }

5.ViewPagerOnTabSelectedListener

这个是TabLayout的监听类,主要目的是,在TabLayout发生页面变化的时候,去同步更新ViewPager2的状态

主要通过ViewPager2的Api,来更新状态viewPager2的状态

 viewPager.setCurrentItem

通过tabLayout的addOnTabSelectedListener 方法来添加监听

tabLayout.addOnTabSelectedListener()
  private static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
    private final ViewPager2 viewPager;
    private final boolean smoothScroll;

    ViewPagerOnTabSelectedListener(ViewPager2 viewPager, boolean smoothScroll) {
      this.viewPager = viewPager;
      this.smoothScroll = smoothScroll;
    }

    @Override
    public void onTabSelected(@NonNull TabLayout.Tab tab) {
      viewPager.setCurrentItem(tab.getPosition(), smoothScroll);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
      // No-op
    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {
      // No-op
    }
  }

6.ViewPagerOnTabSelectedListener

通过viewPager2的适配器监听类来更新的tabLayout状态

private class PagerAdapterObserver extends RecyclerView.AdapterDataObserver {
    PagerAdapterObserver() {}

    @Override
    public void onChanged() {
      populateTabsFromPagerAdapter();
    }

    @Override
    public void onItemRangeChanged(int positionStart, int itemCount) {
      populateTabsFromPagerAdapter();
    }

    @Override
    public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
      populateTabsFromPagerAdapter();
    }

    @Override
    public void onItemRangeInserted(int positionStart, int itemCount) {
      populateTabsFromPagerAdapter();
    }

    @Override
    public void onItemRangeRemoved(int positionStart, int itemCount) {
      populateTabsFromPagerAdapter();
    }

    @Override
    public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
      populateTabsFromPagerAdapter();
    }
  }

从上面的ViewPager2的适配器监听 ,收到数据的变化,就去更新tabLayout 状态,调用populateTabsFromPagerAdapter 函数

主要是根据数据的条目,更新tab的数量,然后,添加到tabLayout 中,注意,在这里通过接口回调的方式,回调了onConfigureTab方法,

调用者,就能够得到里面的tab的相关信息

@SuppressWarnings("WeakerAccess")
  void populateTabsFromPagerAdapter() {
    tabLayout.removeAllTabs();

    if (adapter != null) {
      int adapterCount = adapter.getItemCount();
      for (int i = 0; i < adapterCount; i++) {
        TabLayout.Tab tab = tabLayout.newTab();
        tabConfigurationStrategy.onConfigureTab(tab, i);
        tabLayout.addTab(tab, false);
      }
      // Make sure we reflect the currently set ViewPager item
      if (adapterCount > 0) {
        int lastItem = tabLayout.getTabCount() - 1;
        int currItem = Math.min(viewPager.getCurrentItem(), lastItem);
        if (currItem != tabLayout.getSelectedTabPosition()) {
          tabLayout.selectTab(tabLayout.getTabAt(currItem));
        }
      }
    }
  }

7.结合ViewPager2跟TabLayout

在这里去注册viewPager2跟Tablayout的各种监听,以及去初始化填充

public void attach() {
    if (attached) {
      throw new IllegalStateException("TabLayoutMediator is already attached");
    }
    adapter = viewPager.getAdapter();
    if (adapter == null) {
      throw new IllegalStateException(
          "TabLayoutMediator attached before ViewPager2 has an " + "adapter");
    }
    attached = true;

    // Add our custom OnPageChangeCallback to the ViewPager
    onPageChangeCallback = new TabLayoutOnPageChangeCallback(tabLayout);
    viewPager.registerOnPageChangeCallback(onPageChangeCallback);

    // Now we'll add a tab selected listener to set ViewPager's current item
    onTabSelectedListener = new ViewPagerOnTabSelectedListener(viewPager, smoothScroll);
    tabLayout.addOnTabSelectedListener(onTabSelectedListener);

    // Now we'll populate ourselves from the pager adapter, adding an observer if
    // autoRefresh is enabled
    if (autoRefresh) {
      // Register our observer on the new adapter
      pagerAdapterObserver = new PagerAdapterObserver();
      adapter.registerAdapterDataObserver(pagerAdapterObserver);
    }

    populateTabsFromPagerAdapter();

    // Now update the scroll position to match the ViewPager's current item
    tabLayout.setScrollPosition(viewPager.getCurrentItem(), 0f, tru

8.外界使用TabLayoutMediator的简单调用事例

adapter = new ViewPagerFragmentAdapter(this, labels);
        viewPager2.setAdapter(adapter);

        TabLayoutMediator mediator = new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                tab.setText(labels[position]);
            }
        });
        viewPager2.setCurrentItem(2, false);
        mediator.attach();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记2022年秋招经历

自我介绍求职体验求职心得 一、自我介绍 学历普通本科&#xff0c;专业是网络工程&#xff0c;在校期间学习主要的是计算机体系方面的知识&#xff0c;根据课程&#xff0c;自学过前端、后端等内容。包括前端三板斧(htmlcssjs)、常用的前端框架(bootstarp/Vue等&#xff09;&am…

Android项目接入React Native方案

本篇文章主要介绍在现有的Android项目中接入React Native的接入过程&#xff0c;分析接入过程中的一些问题和解决方案&#xff0c;接入RN的平台为Android&#xff0c;开发环境为Mac&#xff0c;开发工具为Android Studio。 一、环境配置 1、Android配置 因为是现有的Android项…

Vue实现DOM元素拖放互换位置

一、拖放和释放HTML 拖放接口使得 web 应用能够在网页中拖放文件。这里将介绍了 web 应用如何接受从底层平台的文件管理器拖动DOM的操作。拖放的主要步骤是为 drop 事件定义一个释放区(释放文件的目标元素) 和为dragover事件定义一个事件处理程序。触发 drop 事件的目标元素需要…

day20IO流

1.字符流 1.1为什么会出现字符流【理解】 字符流的介绍 由于字节流操作中文不是特别的方便&#xff0c;所以Java就提供字符流 字符流 字节流 编码表 中文的字节存储方式 用字节流复制文本文件时&#xff0c;文本文件也会有中文&#xff0c;但是没有问题&#xff0c;原因是最…

数学建模-分类模型(SPSS)

目录 1.简介 2.样例-二元 1.对于预测结果不理想&#xff0c;在logistics模型里加入平方项交互项等。 2.如果自变量有分类变量&#xff08;如男女&#xff0c;行业有互联网行业、旅游行业……&#xff09; 3.分训练集、测试集 4.fisher线性判别分析 3.样例-多元 注意&…

【Nginx】使用Docker完成Nginx反向代理

本机是在CentOS7上面进行操作的 1.首先安装好Dokcer&#xff0c;这里不再赘述 2.Docker安装Nginx容器 2.1首先需要创建Nginx配置文件&#xff0c;之后完成挂载 启动前需要先创建Nginx外部挂载的配置文件&#xff08; /home/nginx/conf/nginx.conf&#xff09; 之所以要先创建…

Redis - Redis 6.0 新特性之客户端缓存

1. 为什么需要客户端缓存 antirez 写了一篇有关客户端缓存设计的想法&#xff1a;《Client side caching in Redis 6》。antirez 认为&#xff0c;Redis 接下来的一个重点是配合客户端&#xff0c;因为客户端缓存显而易见的可以减轻 Redis 的压力&#xff0c;速度也快很多。实…

Android从开机到APP启动流程——基于Android9.0

Android从开机到APP启动流程——基于Android9.0 一、 Zygote进程启动流程 二、 System Server启动流程 三、 ActivityManagerService启动流程 四、 Launcher App (Home Activity)启动流程 五、 Zygote fork()子进程&#xff0c;子进程入口为ActivityThread.main() 六、 Acti…

第02讲:使用kubeadm搭建k8s集群的准备工作

官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/ kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具&#xff0c;这个工具能通过两条指令完成一个 kubernetes 集群的部署: 第1步、创建一个 Master 节点 kubeadm init第2步&#x…

记录一次mysql慢查询的优化过程

前言 业务上线后经常报查询超时&#xff0c;数据库使用的是阿里云的RDS&#xff0c;mysql版本是5.6.16-log&#xff0c;有几条统计数据的查询语句执行很慢&#xff0c;有的甚至执行一次需要10多秒&#xff0c;简直无法忍受。 查看了超时时间&#xff0c;默认为0 show variables…

【微信小程序-原生开发】实用教程03-自定义底部导航(含自定义tabBar导航高亮需点击两次的解决方案)

开始前&#xff0c;请先完成底部导航的开发&#xff0c;详见 【微信小程序-原生开发】实用教程02-添加全局页面配置、页面、底部导航 https://sunshinehu.blog.csdn.net/article/details/128705866 显然&#xff0c;纯文字的底部导航有点low&#xff0c;还是需要有图标的才酷…

新手编写IntelliJ IDEA插件

需求目的可能你会想什么场景会需要用到插件开发&#xff0c;其实插件开发算是一种通用的解决方案&#xff0c;由服务平台定义标准让各自使用方进行自需的扩展。这就像我们非常常用的 P3C 代码检查插件、代码审计插件、脚手架工程创建插件、自动化API提取插件、单元测试统计插件…

TOF相机国产、非国产统计参数对比分析

TOF相机国产、非国产统计参数对比分析 Kinect v2 Kinect v2是Microsoft在2014年发售的&#xff0c;如图1-1所示。相比于Kinect v1在硬件和软件上作出了很大的进化&#xff0c;且在深度测量的系统和非系统误差方面表现出更好的性能。 Kinect v2中一共有三个摄像头&#xff0c…

Linux学习笔记【part2】网络配置与远程登录

Linux基础篇学习笔记 1.网络连接模式 VMware 提供了三种网络连接模式&#xff1a; ① 桥接模式 桥接模式&#xff1a;虚拟机直接连接外部物理网络的模式&#xff0c;主机起到了网桥的作用。在这种模式下&#xff0c;虚拟机可以直接访问外部网络&#xff0c;并且对外部网络是…

vue3利用keepAlive缓存页面

场景介绍 项目中经常会有这么一个需求&#xff0c;一个表单页面&#xff0c;可能需要跳转其他页面拿到对应的数据&#xff0c;再跳回表单页面&#xff0c;但是之前填写过的数据还在。而某些页面跳这个表单页面的时候&#xff0c;是不需要缓存&#xff0c;因为他是新增&#xf…

通过Facebook建立反链:SEO角度

最近我有一个朋友的网站做得很不错&#xff0c;每天都在增加反链。反链对于网站来说&#xff0c;好处是显而易见的&#xff0c;能够提升搜索引擎对网站的认可度&#xff0c;增强用户对网站的信任度。另外一个方面的好处是&#xff0c;反链可以提高流量&#xff08;或者转化率&a…

想考个PMP证书,要怎么报考?

pmp 报考条件没他们说的那么难&#xff0c;什么 4500/7500 个小时的项目管理经验&#xff0c;这个条件看起来很难&#xff0c;其实项目无处不在&#xff0c;画一幅画&#xff0c;做一餐饭&#xff0c;都能算一个项目&#xff0c;这 4500个小时、7500 个小时很快就达到了。一、报…

三十、Kubernetes中kube-proxy三种工作模式详解

1、概述 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题&#xff0c;kubernetes提供了Service资源&…

2023-01-18 ClickHouse之聚合功能源码分析

前言 聚合分析是从海量数据中提取数据的基本方法&#xff0c;对于OLAP数据库而言&#xff0c;聚合分析是其关键能力之一&#xff0c;ClickHouse在这方面也做了很多设计和优化&#xff0c;正如ClickHouse在文档中所述&#xff1a; 本文将分析展示ClickHouse的聚合功能的工作原理…

NFS 导出的共享信息披露漏洞问题解法

输入&#xff1a;shoumount -e&#xff0c; 如果有目录信息&#xff0c;则说明有NFS 导出的共享信息披露漏洞。 如果处理了就应显示如下图&#xff1a; 解法如下&#xff1a; 1&#xff09;备份需要修改的文件 cp /etc/hosts.allow /etc/hosts.allowbak cp /etc/hosts.deny…