@@ -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
0 commit comments