Skip to content

Commit 2af3196

Browse files
committed
[TabLayoutMediator] Support responding to adapter changes
1 parent 690bbfc commit 2af3196

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

lib/java/com/google/android/material/tabs/TabLayoutMediator.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE;
2121
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING;
2222

23+
import android.view.ViewTreeObserver;
2324
import androidx.recyclerview.widget.RecyclerView;
2425
import androidx.annotation.NonNull;
2526
import androidx.annotation.Nullable;
@@ -39,8 +40,7 @@
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
*/
4646
public 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

Comments
 (0)