13
13
import android .graphics .Rect ;
14
14
import android .graphics .drawable .ColorDrawable ;
15
15
import android .graphics .drawable .Drawable ;
16
- import android . support . v4 .widget .NestedScrollView ;
17
- import android . support . v4 .view .ViewCompat ;
16
+ import androidx . core .widget .NestedScrollView ;
17
+ import androidx . core .view .ViewCompat ;
18
18
import android .util .Log ;
19
19
import android .view .MotionEvent ;
20
20
import android .view .View ;
@@ -61,9 +61,7 @@ public class ReactNestedScrollView extends NestedScrollView implements ReactClip
61
61
private boolean mActivelyScrolling ;
62
62
private @ Nullable Rect mClippingRect ;
63
63
private @ Nullable String mOverflow = ViewProps .HIDDEN ;
64
- private boolean mDoneFlinging ;
65
64
private boolean mDragging ;
66
- private boolean mFlinging ;
67
65
private boolean mPagingEnabled = false ;
68
66
private @ Nullable Runnable mPostTouchRunnable ;
69
67
private boolean mRemoveClippedSubviews ;
@@ -76,6 +74,8 @@ public class ReactNestedScrollView extends NestedScrollView implements ReactClip
76
74
private int mSnapInterval = 0 ;
77
75
private float mDecelerationRate = 0.985f ;
78
76
private @ Nullable List <Integer > mSnapOffsets ;
77
+ private boolean mSnapToStart = true ;
78
+ private boolean mSnapToEnd = true ;
79
79
private View mContentView ;
80
80
private ReactViewBackgroundManager mReactBackgroundManager ;
81
81
@@ -164,6 +164,13 @@ public void setSnapOffsets(List<Integer> snapOffsets) {
164
164
mSnapOffsets = snapOffsets ;
165
165
}
166
166
167
+ public void setSnapToStart (boolean snapToStart ) {
168
+ mSnapToStart = snapToStart ;
169
+ }
170
+ public void setSnapToEnd (boolean snapToEnd ) {
171
+ mSnapToEnd = snapToEnd ;
172
+ }
173
+
167
174
public void flashScrollIndicators () {
168
175
awakenScrollBars ();
169
176
}
@@ -307,8 +314,21 @@ public void getClippingRect(Rect outClippingRect) {
307
314
308
315
@ Override
309
316
public void fling (int velocityY ) {
317
+ // Workaround.
318
+ // On Android P if a ScrollView is inverted, we will get a wrong sign for
319
+ // velocityY (see https://issuetracker.google.com/issues/112385925).
320
+ // At the same time, mOnScrollDispatchHelper tracks the correct velocity direction.
321
+ //
322
+ // Hence, we can use the absolute value from whatever the OS gives
323
+ // us and use the sign of what mOnScrollDispatchHelper has tracked.
324
+ float signum = Math .signum (mOnScrollDispatchHelper .getYFlingVelocity ());
325
+ if (signum == 0 ) {
326
+ signum = Math .signum (velocityY );
327
+ }
328
+ final int correctedVelocityY = (int )(Math .abs (velocityY ) * signum );
329
+
310
330
if (mPagingEnabled ) {
311
- flingAndSnap (velocityY );
331
+ flingAndSnap (correctedVelocityY );
312
332
} else if (mScroller != null ) {
313
333
// FB SCROLLVIEW CHANGE
314
334
@@ -324,7 +344,7 @@ public void fling(int velocityY) {
324
344
getScrollX (), // startX
325
345
getScrollY (), // startY
326
346
0 , // velocityX
327
- velocityY , // velocityY
347
+ correctedVelocityY , // velocityY
328
348
0 , // minX
329
349
0 , // maxX
330
350
0 , // minY
@@ -335,14 +355,14 @@ public void fling(int velocityY) {
335
355
336
356
ViewCompat .postInvalidateOnAnimation (this );
337
357
338
- // RNNestedScrollView CHANGE
358
+ // RNNestedScrollView CHANGE (Should we use correctedVelocityY here as well?)
339
359
// Fixed fling issue on support library 26 (see issue https://github.com/cesardeazevedo/react-native-nested-scroll-view/issues/16)
340
360
super .fling (velocityY );
341
361
// END FB SCROLLVIEW CHANGE
342
362
} else {
343
- super .fling (velocityY );
363
+ super .fling (correctedVelocityY );
344
364
}
345
- handlePostTouchScrolling (0 , velocityY );
365
+ handlePostTouchScrolling (0 , correctedVelocityY );
346
366
}
347
367
348
368
private void enableFpsListener () {
@@ -575,10 +595,29 @@ private void flingAndSnap(int velocityY) {
575
595
? smallerOffset
576
596
: largerOffset ;
577
597
578
- // Chose the correct snap offset based on velocity
579
- if (velocityY > 0 ) {
598
+ // if scrolling after the last snap offset and snapping to the
599
+ // end of the list is disabled, then we allow free scrolling
600
+ if (!mSnapToEnd && targetOffset >= lastOffset ) {
601
+ if (getScrollY () >= lastOffset ) {
602
+ // free scrolling
603
+ } else {
604
+ // snap to end
605
+ targetOffset = lastOffset ;
606
+ }
607
+ } else if (!mSnapToStart && targetOffset <= firstOffset ) {
608
+ if (getScrollY () <= firstOffset ) {
609
+ // free scrolling
610
+ } else {
611
+ // snap to beginning
612
+ targetOffset = firstOffset ;
613
+ }
614
+ } else if (velocityY > 0 ) {
615
+ // when snapping velocity can feel sluggish for slow swipes
616
+ velocityY += (int ) ((largerOffset - targetOffset ) * 10.0 );
580
617
targetOffset = largerOffset ;
581
618
} else if (velocityY < 0 ) {
619
+ // when snapping velocity can feel sluggish for slow swipes
620
+ velocityY -= (int ) ((targetOffset - smallerOffset ) * 10.0 );
582
621
targetOffset = smallerOffset ;
583
622
} else {
584
623
targetOffset = nearestOffset ;
@@ -634,7 +673,7 @@ public void setEndFillColor(int color) {
634
673
635
674
@ Override
636
675
protected void onOverScrolled (int scrollX , int scrollY , boolean clampedX , boolean clampedY ) {
637
- if (mScroller != null ) {
676
+ if (mScroller != null && mContentView != null ) {
638
677
// FB SCROLLVIEW CHANGE
639
678
640
679
// This is part two of the reimplementation of fling to fix the bounce-back bug. See #fling() for
0 commit comments