I want to use com.google.android.material.tabs.TabLayout
component with Android\'s new ViewPager
implementation androidx.viewpager2.widget.Vi
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.
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>
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)
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.
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.
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));
}
});