@@ -262,7 +262,7 @@ public boolean onTouchEvent(MotionEvent ev) {
262
262
@ Override
263
263
public void fling (int velocityX ) {
264
264
if (mPagingEnabled ) {
265
- smoothScrollAndSnap (velocityX );
265
+ flingAndSnap (velocityX );
266
266
} else if (mScroller != null ) {
267
267
// FB SCROLLVIEW CHANGE
268
268
@@ -440,7 +440,7 @@ public void run() {
440
440
// Only if we have pagingEnabled and we have not snapped to the page do we
441
441
// need to continue checking for the scroll. And we cause that scroll by asking for it
442
442
mSnappingToPage = true ;
443
- smoothScrollAndSnap (0 );
443
+ flingAndSnap (0 );
444
444
ViewCompat .postOnAnimationDelayed (ReactHorizontalScrollView .this ,
445
445
this ,
446
446
ReactScrollViewHelper .MOMENTUM_DELAY );
@@ -459,28 +459,15 @@ public void run() {
459
459
ReactScrollViewHelper .MOMENTUM_DELAY );
460
460
}
461
461
462
- /**
463
- * This will smooth scroll us to the nearest snap offset point
464
- * It currently just looks at where the content is and slides to the nearest point.
465
- * It is intended to be run after we are done scrolling, and handling any momentum scrolling.
466
- */
467
- private void smoothScrollAndSnap (int velocityX ) {
468
- if (getChildCount () <= 0 ) {
469
- return ;
470
- }
471
-
472
- int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
473
- int targetOffset = 0 ;
474
- int smallerOffset = 0 ;
475
- int largerOffset = maximumOffset ;
476
-
462
+ private int predictFinalScrollPosition (int velocityX ) {
477
463
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
478
464
// no way to customize the scroll duration. So, we create a temporary OverScroller
479
465
// so we can predict where a fling would land and snap to nearby that point.
480
466
OverScroller scroller = new OverScroller (getContext ());
481
467
scroller .setFriction (1.0f - mDecelerationRate );
482
468
483
469
// predict where a fling would end up so we can scroll to the nearest snap offset
470
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
484
471
int width = getWidth () - getPaddingStart () - getPaddingEnd ();
485
472
scroller .fling (
486
473
getScrollX (), // startX
@@ -494,7 +481,76 @@ private void smoothScrollAndSnap(int velocityX) {
494
481
width /2 , // overX
495
482
0 // overY
496
483
);
497
- targetOffset = scroller .getFinalX ();
484
+ return scroller .getFinalX ();
485
+ }
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 velocity ) {
493
+ double interval = (double ) getSnapInterval ();
494
+ double currentOffset = (double ) getScrollX ();
495
+ double targetOffset = (double ) predictFinalScrollPosition (velocity );
496
+
497
+ int previousPage = (int ) Math .floor (currentOffset / interval );
498
+ int nextPage = (int ) Math .ceil (currentOffset / interval );
499
+ int currentPage = (int ) Math .round (currentOffset / interval );
500
+ int targetPage = (int ) Math .round (targetOffset / interval );
501
+
502
+ if (velocity > 0 && nextPage == previousPage ) {
503
+ nextPage ++;
504
+ } else if (velocity < 0 && previousPage == nextPage ) {
505
+ previousPage --;
506
+ }
507
+
508
+ if (
509
+ // if scrolling towards next page
510
+ velocity > 0 &&
511
+ // and the middle of the page hasn't been crossed already
512
+ currentPage < nextPage &&
513
+ // and it would have been crossed after flinging
514
+ targetPage > previousPage
515
+ ) {
516
+ currentPage = nextPage ;
517
+ }
518
+ else if (
519
+ // if scrolling towards previous page
520
+ velocity < 0 &&
521
+ // and the middle of the page hasn't been crossed already
522
+ currentPage > previousPage &&
523
+ // and it would have been crossed after flinging
524
+ targetPage < nextPage
525
+ ) {
526
+ currentPage = previousPage ;
527
+ }
528
+
529
+ targetOffset = currentPage * interval ;
530
+ if (targetOffset != currentOffset ) {
531
+ mActivelyScrolling = true ;
532
+ smoothScrollTo ((int ) targetOffset , getScrollY ());
533
+ }
534
+ }
535
+
536
+ private void flingAndSnap (int velocityX ) {
537
+ if (getChildCount () <= 0 ) {
538
+ return ;
539
+ }
540
+
541
+ // pagingEnabled only allows snapping one interval at a time
542
+ if (mSnapInterval == 0 && mSnapOffsets == null ) {
543
+ smoothScrollAndSnap (velocityX );
544
+ return ;
545
+ }
546
+
547
+ int maximumOffset = Math .max (0 , computeHorizontalScrollRange () - getWidth ());
548
+ int targetOffset = predictFinalScrollPosition (velocityX );
549
+ int smallerOffset = 0 ;
550
+ int largerOffset = maximumOffset ;
551
+ int firstOffset = 0 ;
552
+ int lastOffset = maximumOffset ;
553
+ int width = getWidth () - getPaddingStart () - getPaddingEnd ();
498
554
499
555
// offsets are from the right edge in RTL layouts
500
556
boolean isRTL = TextUtilsCompat .getLayoutDirectionFromLocale (Locale .getDefault ()) == ViewCompat .LAYOUT_DIRECTION_RTL ;
0 commit comments