How to use TabLayout with ViewPager2 in Android

前端 未结 7 1738
春和景丽
春和景丽 2020-12-29 18:24

I want to use com.google.android.material.tabs.TabLayout component with Android\'s new ViewPager implementation androidx.viewpager2.widget.Vi

相关标签:
7条回答
  • 2020-12-29 19:15

    No hacks, no extensions, no TabLayoutMediator

    I am on implementation 'com.google.android.material:material:1.2.0-alpha02' and do the following without needing the TabLayoutMediator. Instead, I link the TabLayout with the ViewPager2 using the method described here. I've also added a working example to github here. I think I've minimized the solution to a minimal working example. I'll explain the important bits.

    Adding the elements to the template

    First we'll need to add the TabLayout and ViewPager2 to the layout. I've placed them inside a LinearLayout and CoordinatorLayout here, but you can do whatever you like of course.

    <!-- activity_main.xml -->
    <?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=".MainActivity">
    
        <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
    
                <com.google.android.material.tabs.TabLayout
                    android:id="@+id/tabLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>
                <androidx.viewpager2.widget.ViewPager2
                    android:id="@+id/pager"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>
    
            </LinearLayout>
    
        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Connecting an adapter to the viewpager

    So the adapter is in charge of supplying the correct fragments to the activity. You'll have to extend FragmentStateAdapter which I've done very simply as below (it's a private class because it's declared within my MainActivity.java here):

        private class ViewStateAdapter extends FragmentStateAdapter {
    
            public ViewStateAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
                super(fragmentManager, lifecycle);
            }
    
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                // Hardcoded in this order, you'll want to use lists and make sure the titles match
                if (position == 0) {
                    return new BarFragment();
                }
                return new FooFragment();
            }
    
            @Override
            public int getItemCount() {
                // Hardcoded, use lists
                return 2;
            }
        }
    

    I can then connect my own Adapter to the ViewPager as below:

    FragmentManager fm = getSupportFragmentManager();
    ViewStateAdapter sa = new ViewStateAdapter(fm, getLifecycle());
    final ViewPager2 pa = findViewById(R.id.pager);
    pa.setAdapter(sa);
    

    I've added the fragments to my viewpager. (Because I hardcoded the Fragments in my adapter, you should use a list and something like an 'addFragment' method or something)

    The TabLayout

    Then with

    TabLayout tabLayout = findViewById(R.id.tabLayout);
    tabLayout.addTab(tabLayout.newTab().setText("Bar"));
    tabLayout.addTab(tabLayout.newTab().setText("Foo"));
    

    I add two tabs to my TabLayout, showing the titles but not letting me switch to the fragments yet.

    Connecting TabLayout to Adapter

    tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    pa.setCurrentItem(tab.getPosition());
                }
    
                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
    
                }
    
                @Override
                public void onTabReselected(TabLayout.Tab tab) {
    
                }
            });
    

    This should be pretty straightforward. User clicks on a tab, I get the position in my callback and I simply set the adapter's current item to that position.

    Change Tab when swiping

    Finally we couple back when the user swipes the fragment to set the correct tab item as selected

    pa.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageSelected(int position) {
            tabLayout.selectTab(tabLayout.getTabAt(position));
        }
    });
    
    0 讨论(0)
提交回复
热议问题