Skip to content

Commit e9246ed

Browse files
imhappidsn5ft
authored andcommitted
[TabLayout] Fix scrolling issue when using scrollable tab layout with viewpager
Resolves #3138 PiperOrigin-RevId: 508444050
1 parent 505460f commit e9246ed

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

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

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,20 @@ public void setScrollPosition(
757757
float positionOffset,
758758
boolean updateSelectedTabView,
759759
boolean updateIndicatorPosition) {
760+
setScrollPosition(
761+
position,
762+
positionOffset,
763+
updateSelectedTabView,
764+
updateIndicatorPosition,
765+
/* alwaysScroll= */ true);
766+
}
767+
768+
void setScrollPosition(
769+
int position,
770+
float positionOffset,
771+
boolean updateSelectedTabView,
772+
boolean updateIndicatorPosition,
773+
boolean alwaysScroll) {
760774
final int roundedPosition = Math.round(position + positionOffset);
761775
if (roundedPosition < 0 || roundedPosition >= slidingTabIndicator.getChildCount()) {
762776
return;
@@ -771,7 +785,36 @@ public void setScrollPosition(
771785
if (scrollAnimator != null && scrollAnimator.isRunning()) {
772786
scrollAnimator.cancel();
773787
}
774-
scrollTo(position < 0 ? 0 : calculateScrollXForTab(position, positionOffset), 0);
788+
int scrollXForPosition = calculateScrollXForTab(position, positionOffset);
789+
int scrollX = getScrollX();
790+
// If the position is smaller than the selected tab position, the position is getting larger
791+
// to reach the selected tab position so scrollX is increasing.
792+
// We only want to update the scroll position if the new scroll position is greater than
793+
// the current scroll position.
794+
// Conversely if the position is greater than the selected tab position, the position is
795+
// getting smaller to reach the selected tab position so scrollX is decreasing.
796+
// We only update the scroll position if the new scroll position is less than the current
797+
// scroll position.
798+
// Lastly if the position is equal to the selected position, we want to set the scroll
799+
// position which also updates the selected tab view and the indicator.
800+
boolean toMove =
801+
(position < getSelectedTabPosition() && scrollXForPosition >= scrollX)
802+
|| (position > getSelectedTabPosition() && scrollXForPosition <= scrollX)
803+
|| (position == getSelectedTabPosition());
804+
// If the layout direction is RTL, the scrollXForPosition and scrollX comparisons are
805+
// reversed since scrollX values remain the same in RTL but tab positions go RTL.
806+
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
807+
toMove =
808+
(position < getSelectedTabPosition() && scrollXForPosition <= scrollX)
809+
|| (position > getSelectedTabPosition()
810+
&& scrollXForPosition >= scrollX)
811+
|| (position == getSelectedTabPosition());
812+
}
813+
// We want to scroll if alwaysScroll is true, the viewpager is being dragged, or if we should
814+
// scroll by the rules above.
815+
if (toMove || viewPagerScrollState == SCROLL_STATE_DRAGGING || alwaysScroll) {
816+
scrollTo(position < 0 ? 0 : scrollXForPosition, 0);
817+
}
775818

776819
// Update the 'selected state' view as we scroll, if enabled
777820
if (updateSelectedTabView) {
@@ -3536,7 +3579,7 @@ public void onPageScrolled(
35363579
final boolean updateIndicator =
35373580
!(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE);
35383581
tabLayout.setScrollPosition(
3539-
position, positionOffset, updateSelectedTabView, updateIndicator);
3582+
position, positionOffset, updateSelectedTabView, updateIndicator, false);
35403583
}
35413584
}
35423585

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse
230230
boolean updateIndicator =
231231
!(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE);
232232
tabLayout.setScrollPosition(
233-
position, positionOffset, updateSelectedTabView, updateIndicator);
233+
position, positionOffset, updateSelectedTabView, updateIndicator, false);
234234
}
235235
}
236236

0 commit comments

Comments
 (0)