2020import static androidx .viewpager2 .widget .ViewPager2 .SCROLL_STATE_IDLE ;
2121import static androidx .viewpager2 .widget .ViewPager2 .SCROLL_STATE_SETTLING ;
2222
23+ import android .view .ViewTreeObserver ;
2324import androidx .recyclerview .widget .RecyclerView ;
2425import androidx .annotation .NonNull ;
2526import androidx .annotation .Nullable ;
3940 * the mediator object, {@link #attach()} will link the TabLayout and the ViewPager2 together. When
4041 * creating an instance of this class, you must supply an implementation of {@link
4142 * TabConfigurationStrategy} in which you set the text of the tab, and/or perform any styling of the
42- * tabs that you require. Changing ViewPager2's adapter will require a {@link #detach()} followed by
43- * {@link #attach()} call. Changing the ViewPager2 or TabLayout will require a new instantiation of
43+ * tabs that you require. Changing the ViewPager2 or TabLayout will require a new instantiation of
4444 * TabLayoutMediator.
4545 */
4646public final class TabLayoutMediator {
@@ -54,6 +54,7 @@ public final class TabLayoutMediator {
5454
5555 @ Nullable private TabLayoutOnPageChangeCallback onPageChangeCallback ;
5656 @ Nullable private TabLayout .OnTabSelectedListener onTabSelectedListener ;
57+ @ Nullable private ViewPagerOnLayoutListener onLayoutListener ;
5758 @ Nullable private RecyclerView .AdapterDataObserver pagerAdapterObserver ;
5859
5960 /**
@@ -127,6 +128,13 @@ public void attach() {
127128 onTabSelectedListener = new ViewPagerOnTabSelectedListener (viewPager , smoothScroll );
128129 tabLayout .addOnTabSelectedListener (onTabSelectedListener );
129130
131+ // Here we'll add a listener that responds to adapter changes. Unlike ViewPager,
132+ // ViewPager2 doesn't have a built-in OnAdapterChangeListener, so we'll use a
133+ // slightly different approach that relies on the fact that changing the adapter
134+ // always causes a layout pass (see b/135299048).
135+ onLayoutListener = new ViewPagerOnLayoutListener ();
136+ viewPager .getViewTreeObserver ().addOnGlobalLayoutListener (onLayoutListener );
137+
130138 // Now we'll populate ourselves from the pager adapter, adding an observer if
131139 // autoRefresh is enabled
132140 if (autoRefresh ) {
@@ -151,8 +159,10 @@ public void detach() {
151159 adapter .unregisterAdapterDataObserver (pagerAdapterObserver );
152160 pagerAdapterObserver = null ;
153161 }
162+ viewPager .getViewTreeObserver ().removeOnGlobalLayoutListener (onLayoutListener );
154163 tabLayout .removeOnTabSelectedListener (onTabSelectedListener );
155164 viewPager .unregisterOnPageChangeCallback (onPageChangeCallback );
165+ onLayoutListener = null ;
156166 onTabSelectedListener = null ;
157167 onPageChangeCallback = null ;
158168 adapter = null ;
@@ -317,4 +327,16 @@ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
317327 populateTabsFromPagerAdapter ();
318328 }
319329 }
330+
331+ private class ViewPagerOnLayoutListener implements ViewTreeObserver .OnGlobalLayoutListener {
332+
333+ @ Override
334+ public void onGlobalLayout () {
335+ RecyclerView .Adapter <?> currentAdapter = viewPager .getAdapter ();
336+ if (adapter != currentAdapter ) {
337+ detach ();
338+ attach ();
339+ }
340+ }
341+ }
320342}
0 commit comments