美文网首页
Android Jetpack :ViewPager2 结合Ta

Android Jetpack :ViewPager2 结合Ta

作者: MiBoy | 来源:发表于2020-08-31 18:57 被阅读0次

    Android 有个ViewPager,但是在Androidx 的jetpack 中出现了ViewPager2,官方也建议使用这个类替代ViewPager,但是之前的TabLayout 都是绑定的ViewPager :

      public void setupWithViewPager(@Nullable ViewPager viewPager) {
        this.setupWithViewPager(viewPager, true);
      }
    
      public void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh) {
        this.setupWithViewPager(viewPager, autoRefresh, false);
      }
    

    那么怎么使用ViewPager2 和TabLayout呢?

    方案一:

    网上已经给出了一个教程,就是 Copy 一个类叫TabLayoutMediator的类,然后放在固定包名下面:com.google.android.material.tabs:

    TabLayoutMediator.png

    方案二:

    更新material 库 到com.google.android.material:material:1.1.0-alpha09@aar及以上,你就会看到Google 爸爸已经自己更新到上面了,好东西不会留着自己用了。

    TabLayoutMediator

    用法

    public class TestConfigActivity extends BaseActivity {
      private List<Fragment> mFragments;
      private final static String[] NAMES = {"a", "b", "c", "d"};
    
      private TabLayoutMediator mLayoutMediator;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_main);
        TabLayout tabLayout = findViewById(R.id.tab_layout);
        initData();
        ViewPager2 viewPager2 = findViewById(R.id.test_view_page);
        viewPager2.setAdapter(new FragmentStateAdapter(this) {
          @NonNull
          @Override
          public Fragment createFragment(int position) {
            return mFragments.get(position);
          }
    
          @Override
          public int getItemCount() {
            return mFragments.size();
          }
        });
    
        mLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, false, true,
            (tab, position) -> tab.setText(NAMES[position]));
    
        mLayoutMediator.attach();
      }
    
    
      private void initData() {
        mFragments = new ArrayList<>();
        mFragments.add(new TestConfigFragment());
        mFragments.add(new TestSwitchFragment());
        mFragments.add(new TestUIFragment());
        mFragments.add(new TestOtherFragment());
      }
    
    
    
      @Override
      protected void onDestroy() {
        super.onDestroy();
        mLayoutMediator.detach();
      }
    }
    

    这个是源码,为啥我会贴源码呢,因为之前这个类是在 Google内部的库的frameWork层,只有内部的一些框架能用到,不想更新 material库的可以直接cp源码,定义好包名的方式去搞。

    TabLayoutMediator 源码

    /*
     * Copyright 2018 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.google.android.material.tabs;
    
    import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_DRAGGING;
    import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE;
    import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.recyclerview.widget.RecyclerView;
    import androidx.viewpager2.widget.ViewPager2;
    import java.lang.ref.WeakReference;
    
    /**
     * A mediator to link a TabLayout with a ViewPager2. The mediator will synchronize the ViewPager2's
     * position with the selected tab when a tab is selected, and the TabLayout's scroll position when
     * the user drags the ViewPager2.
     *
     * <p>Establish the link by creating an instance of this class, make sure the ViewPager2 has an
     * adapter and then call {@link #attach()} on it. When creating an instance of this class, you must
     * supply an implementation of {@link OnConfigureTabCallback} in which you set the text of the tab,
     * and/or perform any styling of the tabs that you require.
     */
    public final class TabLayoutMediator {
      @NonNull private final TabLayout tabLayout;
      @NonNull private final ViewPager2 viewPager;
      private final boolean autoRefresh;
      private final OnConfigureTabCallback onConfigureTabCallback;
      private RecyclerView.Adapter<?> adapter;
      private boolean attached;
    
      private TabLayoutOnPageChangeCallback onPageChangeCallback;
      private TabLayout.OnTabSelectedListener onTabSelectedListener;
      private RecyclerView.AdapterDataObserver pagerAdapterObserver;
    
      /**
       * 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 {@link
         * TabLayout.Tab#setText(CharSequence)}, but any form of styling can be applied.
         *
         * @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);
      }
    
      public TabLayoutMediator(
          @NonNull TabLayout tabLayout,
          @NonNull ViewPager2 viewPager,
          @NonNull OnConfigureTabCallback onConfigureTabCallback) {
        this(tabLayout, viewPager, true, onConfigureTabCallback);
      }
    
      public TabLayoutMediator(
          @NonNull TabLayout tabLayout,
          @NonNull ViewPager2 viewPager,
          boolean autoRefresh,
          @NonNull OnConfigureTabCallback onConfigureTabCallback) {
        this.tabLayout = tabLayout;
        this.viewPager = viewPager;
        this.autoRefresh = autoRefresh;
        this.onConfigureTabCallback = onConfigureTabCallback;
      }
    
      /**
       * Link the TabLayout and the ViewPager2 together.
       *
       * @throws IllegalStateException If the mediator is already attached, or the ViewPager2 has no
       *     adapter.
       */
      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);
        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, true);
      }
    
      /** Unlink the TabLayout and the ViewPager */
      public void detach() {
        adapter.unregisterAdapterDataObserver(pagerAdapterObserver);
        tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
        viewPager.unregisterOnPageChangeCallback(onPageChangeCallback);
        pagerAdapterObserver = null;
        onTabSelectedListener = null;
        onPageChangeCallback = null;
        attached = false;
      }
    
      @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();
            onConfigureTabCallback.onConfigureTab(tab, i);
            tabLayout.addTab(tab, false);
          }
    
          // Make sure we reflect the currently set ViewPager item
          if (adapterCount > 0) {
            int currItem = viewPager.getCurrentItem();
            if (currItem != tabLayout.getSelectedTabPosition()) {
              tabLayout.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> 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;
        }
      }
    
      /**
       * 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 viewPager;
    
        ViewPagerOnTabSelectedListener(ViewPager2 viewPager) {
          this.viewPager = viewPager;
        }
    
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
          viewPager.setCurrentItem(tab.getPosition(), true);
        }
    
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
          // No-op
        }
    
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
          // No-op
        }
      }
    
      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();
        }
      }
    }
    
    

    相关文章

      网友评论

          本文标题:Android Jetpack :ViewPager2 结合Ta

          本文链接:https://www.haomeiwen.com/subject/jjrpsktx.html