@@ -287,7 +287,7 @@ public boolean onTouchEvent(MotionEvent ev) {
287
287
@ Override
288
288
public void fling (int velocityX ) {
289
289
if (mPagingEnabled ) {
290
- smoothScrollAndSnap (velocityX );
290
+ flingAndSnap (velocityX );
291
291
} else if (mScroller != null ) {
292
292
// FB SCROLLVIEW CHANGE
293
293
@@ -465,7 +465,7 @@ public void run() {
465
465
// Only if we have pagingEnabled and we have not snapped to the page do we
466
466
// need to continue checking for the scroll. And we cause that scroll by asking for it
467
467
mSnappingToPage = true ;
468
- smoothScrollAndSnap (0 );
468
+ flingAndSnap (0 );
469
469
ViewCompat .postOnAnimationDelayed (ReactHorizontalScrollView .this ,
470
470
this ,
471
471
ReactScrollViewHelper .MOMENTUM_DELAY );
@@ -484,30 +484,15 @@ public void run() {
484
484
ReactScrollViewHelper .MOMENTUM_DELAY );
485
485
}
486
486
487
- /**
488
- * This will smooth scroll us to the nearest snap offset point
489
- * It currently just looks at where the content is and slides to the nearest point.
490
- * It is intended to be run after we are done scrolling, and handling any momentum scrolling.
491
- */
492
- private void smoothScrollAndSnap (int velocityX ) {
493
- if (getChildCount () <= 0 ) {
494
- return ;
495
- }
496
-
497
- int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
498
- int targetOffset = 0 ;
499
- int smallerOffset = 0 ;
500
- int largerOffset = maximumOffset ;
501
- int firstOffset = 0 ;
502
- int lastOffset = maximumOffset ;
503
-
487
+ private int predictFinalScrollPosition (int velocityX ) {
504
488
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
505
489
// no way to customize the scroll duration. So, we create a temporary OverScroller
506
490
// so we can predict where a fling would land and snap to nearby that point.
507
491
OverScroller scroller = new OverScroller (getContext ());
508
492
scroller .setFriction (1.0f - mDecelerationRate );
509
493
510
494
// predict where a fling would end up so we can scroll to the nearest snap offset
495
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
511
496
int width = getWidth () - getPaddingStart () - getPaddingEnd ();
512
497
scroller .fling (
513
498
getScrollX (), // startX
@@ -521,7 +506,76 @@ private void smoothScrollAndSnap(int velocityX) {
521
506
width /2 , // overX
522
507
0 // overY
523
508
);
524
- targetOffset = scroller .getFinalX ();
509
+ return scroller .getFinalX ();
510
+ }
511
+
512
+ /**
513
+ * This will smooth scroll us to the nearest snap offset point
514
+ * It currently just looks at where the content is and slides to the nearest point.
515
+ * It is intended to be run after we are done scrolling, and handling any momentum scrolling.
516
+ */
517
+ private void smoothScrollAndSnap (int velocity ) {
518
+ double interval = (double ) getSnapInterval ();
519
+ double currentOffset = (double ) getScrollX ();
520
+ double targetOffset = (double ) predictFinalScrollPosition (velocity );
521
+
522
+ int previousPage = (int ) Math .floor (currentOffset / interval );
523
+ int nextPage = (int ) Math .ceil (currentOffset / interval );
524
+ int currentPage = (int ) Math .round (currentOffset / interval );
525
+ int targetPage = (int ) Math .round (targetOffset / interval );
526
+
527
+ if (velocity > 0 && nextPage == previousPage ) {
528
+ nextPage ++;
529
+ } else if (velocity < 0 && previousPage == nextPage ) {
530
+ previousPage --;
531
+ }
532
+
533
+ if (
534
+ // if scrolling towards next page
535
+ velocity > 0 &&
536
+ // and the middle of the page hasn't been crossed already
537
+ currentPage < nextPage &&
538
+ // and it would have been crossed after flinging
539
+ targetPage > previousPage
540
+ ) {
541
+ currentPage = nextPage ;
542
+ }
543
+ else if (
544
+ // if scrolling towards previous page
545
+ velocity < 0 &&
546
+ // and the middle of the page hasn't been crossed already
547
+ currentPage > previousPage &&
548
+ // and it would have been crossed after flinging
549
+ targetPage < nextPage
550
+ ) {
551
+ currentPage = previousPage ;
552
+ }
553
+
554
+ targetOffset = currentPage * interval ;
555
+ if (targetOffset != currentOffset ) {
556
+ mActivelyScrolling = true ;
557
+ smoothScrollTo ((int ) targetOffset , getScrollY ());
558
+ }
559
+ }
560
+
561
+ private void flingAndSnap (int velocityX ) {
562
+ if (getChildCount () <= 0 ) {
563
+ return ;
564
+ }
565
+
566
+ // pagingEnabled only allows snapping one interval at a time
567
+ if (mSnapInterval == 0 && mSnapOffsets == null ) {
568
+ smoothScrollAndSnap (velocityX );
569
+ return ;
570
+ }
571
+
572
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
573
+ int targetOffset = predictFinalScrollPosition (velocityX );
574
+ int smallerOffset = 0 ;
575
+ int largerOffset = maximumOffset ;
576
+ int firstOffset = 0 ;
577
+ int lastOffset = maximumOffset ;
578
+ int width = getWidth () - getPaddingStart () - getPaddingEnd ();
525
579
526
580
// offsets are from the right edge in RTL layouts
527
581
boolean isRTL = TextUtilsCompat .getLayoutDirectionFromLocale (Locale .getDefault ()) == ViewCompat .LAYOUT_DIRECTION_RTL ;
0 commit comments