@@ -211,7 +211,7 @@ public void requestChildFocus(View child, View focused) {
211
211
if (focused != null && !mPagingEnabled ) {
212
212
scrollToChild (focused );
213
213
}
214
- super .requestChildFocus (child , focused );
214
+ super .requestChildFocus (child , focused );
215
215
}
216
216
217
217
@ Override
@@ -386,7 +386,7 @@ public boolean onTouchEvent(MotionEvent ev) {
386
386
@ Override
387
387
public void fling (int velocityX ) {
388
388
if (mPagingEnabled ) {
389
- smoothScrollAndSnap (velocityX );
389
+ flingAndSnap (velocityX );
390
390
} else if (mScroller != null ) {
391
391
// FB SCROLLVIEW CHANGE
392
392
@@ -564,7 +564,7 @@ public void run() {
564
564
// Only if we have pagingEnabled and we have not snapped to the page do we
565
565
// need to continue checking for the scroll. And we cause that scroll by asking for it
566
566
mSnappingToPage = true ;
567
- smoothScrollAndSnap (0 );
567
+ flingAndSnap (0 );
568
568
ViewCompat .postOnAnimationDelayed (ReactHorizontalScrollView .this ,
569
569
this ,
570
570
ReactScrollViewHelper .MOMENTUM_DELAY );
@@ -583,28 +583,15 @@ public void run() {
583
583
ReactScrollViewHelper .MOMENTUM_DELAY );
584
584
}
585
585
586
- /**
587
- * This will smooth scroll us to the nearest snap offset point
588
- * It currently just looks at where the content is and slides to the nearest point.
589
- * It is intended to be run after we are done scrolling, and handling any momentum scrolling.
590
- */
591
- private void smoothScrollAndSnap (int velocityX ) {
592
- if (getChildCount () <= 0 ) {
593
- return ;
594
- }
595
-
596
- int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
597
- int targetOffset = 0 ;
598
- int smallerOffset = 0 ;
599
- int largerOffset = maximumOffset ;
600
-
586
+ private int predictFinalScrollPosition (int velocityX ) {
601
587
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
602
588
// no way to customize the scroll duration. So, we create a temporary OverScroller
603
589
// so we can predict where a fling would land and snap to nearby that point.
604
590
OverScroller scroller = new OverScroller (getContext ());
605
591
scroller .setFriction (1.0f - mDecelerationRate );
606
592
607
593
// predict where a fling would end up so we can scroll to the nearest snap offset
594
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
608
595
int width = getWidth () - getPaddingStart () - getPaddingEnd ();
609
596
scroller .fling (
610
597
getScrollX (), // startX
@@ -618,7 +605,76 @@ private void smoothScrollAndSnap(int velocityX) {
618
605
width /2 , // overX
619
606
0 // overY
620
607
);
621
- targetOffset = scroller .getFinalX ();
608
+ return scroller .getFinalX ();
609
+ }
610
+
611
+ /**
612
+ * This will smooth scroll us to the nearest snap offset point
613
+ * It currently just looks at where the content is and slides to the nearest point.
614
+ * It is intended to be run after we are done scrolling, and handling any momentum scrolling.
615
+ */
616
+ private void smoothScrollAndSnap (int velocity ) {
617
+ double interval = (double ) getSnapInterval ();
618
+ double currentOffset = (double ) getScrollX ();
619
+ double targetOffset = (double ) predictFinalScrollPosition (velocity );
620
+
621
+ int previousPage = (int ) Math .floor (currentOffset / interval );
622
+ int nextPage = (int ) Math .ceil (currentOffset / interval );
623
+ int currentPage = (int ) Math .round (currentOffset / interval );
624
+ int targetPage = (int ) Math .round (targetOffset / interval );
625
+
626
+ if (velocity > 0 && nextPage == previousPage ) {
627
+ nextPage ++;
628
+ } else if (velocity < 0 && previousPage == nextPage ) {
629
+ previousPage --;
630
+ }
631
+
632
+ if (
633
+ // if scrolling towards next page
634
+ velocity > 0 &&
635
+ // and the middle of the page hasn't been crossed already
636
+ currentPage < nextPage &&
637
+ // and it would have been crossed after flinging
638
+ targetPage > previousPage
639
+ ) {
640
+ currentPage = nextPage ;
641
+ }
642
+ else if (
643
+ // if scrolling towards previous page
644
+ velocity < 0 &&
645
+ // and the middle of the page hasn't been crossed already
646
+ currentPage > previousPage &&
647
+ // and it would have been crossed after flinging
648
+ targetPage < nextPage
649
+ ) {
650
+ currentPage = previousPage ;
651
+ }
652
+
653
+ targetOffset = currentPage * interval ;
654
+ if (targetOffset != currentOffset ) {
655
+ mActivelyScrolling = true ;
656
+ smoothScrollTo ((int ) targetOffset , getScrollY ());
657
+ }
658
+ }
659
+
660
+ private void flingAndSnap (int velocityX ) {
661
+ if (getChildCount () <= 0 ) {
662
+ return ;
663
+ }
664
+
665
+ // pagingEnabled only allows snapping one interval at a time
666
+ if (mSnapInterval == 0 && mSnapOffsets == null ) {
667
+ smoothScrollAndSnap (velocityX );
668
+ return ;
669
+ }
670
+
671
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
672
+ int targetOffset = predictFinalScrollPosition (velocityX );
673
+ int smallerOffset = 0 ;
674
+ int largerOffset = maximumOffset ;
675
+ int firstOffset = 0 ;
676
+ int lastOffset = maximumOffset ;
677
+ int width = getWidth () - getPaddingStart () - getPaddingEnd ();
622
678
623
679
// offsets are from the right edge in RTL layouts
624
680
boolean isRTL = TextUtilsCompat .getLayoutDirectionFromLocale (Locale .getDefault ()) == ViewCompat .LAYOUT_DIRECTION_RTL ;
0 commit comments