重学Android之View——TabLayoutMediator解析

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

重学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();
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android