Skip to content

Commit 017f8bf

Browse files
1 parent 3307332 commit 017f8bf

File tree

3 files changed

+356
-182
lines changed

3 files changed

+356
-182
lines changed

android/src/main/java/com/rnnestedscrollview/ReactNestedScrollView.java

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import android.graphics.Rect;
1414
import android.graphics.drawable.ColorDrawable;
1515
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;
1818
import android.util.Log;
1919
import android.view.MotionEvent;
2020
import android.view.View;
@@ -61,9 +61,7 @@ public class ReactNestedScrollView extends NestedScrollView implements ReactClip
6161
private boolean mActivelyScrolling;
6262
private @Nullable Rect mClippingRect;
6363
private @Nullable String mOverflow = ViewProps.HIDDEN;
64-
private boolean mDoneFlinging;
6564
private boolean mDragging;
66-
private boolean mFlinging;
6765
private boolean mPagingEnabled = false;
6866
private @Nullable Runnable mPostTouchRunnable;
6967
private boolean mRemoveClippedSubviews;
@@ -76,6 +74,8 @@ public class ReactNestedScrollView extends NestedScrollView implements ReactClip
7674
private int mSnapInterval = 0;
7775
private float mDecelerationRate = 0.985f;
7876
private @Nullable List<Integer> mSnapOffsets;
77+
private boolean mSnapToStart = true;
78+
private boolean mSnapToEnd = true;
7979
private View mContentView;
8080
private ReactViewBackgroundManager mReactBackgroundManager;
8181

@@ -164,6 +164,13 @@ public void setSnapOffsets(List<Integer> snapOffsets) {
164164
mSnapOffsets = snapOffsets;
165165
}
166166

167+
public void setSnapToStart(boolean snapToStart) {
168+
mSnapToStart = snapToStart;
169+
}
170+
public void setSnapToEnd(boolean snapToEnd) {
171+
mSnapToEnd = snapToEnd;
172+
}
173+
167174
public void flashScrollIndicators() {
168175
awakenScrollBars();
169176
}
@@ -307,8 +314,21 @@ public void getClippingRect(Rect outClippingRect) {
307314

308315
@Override
309316
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+
310330
if (mPagingEnabled) {
311-
flingAndSnap(velocityY);
331+
flingAndSnap(correctedVelocityY);
312332
} else if (mScroller != null) {
313333
// FB SCROLLVIEW CHANGE
314334

@@ -324,7 +344,7 @@ public void fling(int velocityY) {
324344
getScrollX(), // startX
325345
getScrollY(), // startY
326346
0, // velocityX
327-
velocityY, // velocityY
347+
correctedVelocityY, // velocityY
328348
0, // minX
329349
0, // maxX
330350
0, // minY
@@ -335,14 +355,14 @@ public void fling(int velocityY) {
335355

336356
ViewCompat.postInvalidateOnAnimation(this);
337357

338-
// RNNestedScrollView CHANGE
358+
// RNNestedScrollView CHANGE (Should we use correctedVelocityY here as well?)
339359
// Fixed fling issue on support library 26 (see issue https://github.com/cesardeazevedo/react-native-nested-scroll-view/issues/16)
340360
super.fling(velocityY);
341361
// END FB SCROLLVIEW CHANGE
342362
} else {
343-
super.fling(velocityY);
363+
super.fling(correctedVelocityY);
344364
}
345-
handlePostTouchScrolling(0, velocityY);
365+
handlePostTouchScrolling(0, correctedVelocityY);
346366
}
347367

348368
private void enableFpsListener() {
@@ -575,10 +595,29 @@ private void flingAndSnap(int velocityY) {
575595
? smallerOffset
576596
: largerOffset;
577597

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);
580617
targetOffset = largerOffset;
581618
} else if (velocityY < 0) {
619+
// when snapping velocity can feel sluggish for slow swipes
620+
velocityY -= (int) ((targetOffset - smallerOffset) * 10.0);
582621
targetOffset = smallerOffset;
583622
} else {
584623
targetOffset = nearestOffset;
@@ -634,7 +673,7 @@ public void setEndFillColor(int color) {
634673

635674
@Override
636675
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
637-
if (mScroller != null) {
676+
if (mScroller != null && mContentView != null) {
638677
// FB SCROLLVIEW CHANGE
639678

640679
// This is part two of the reimplementation of fling to fix the bounce-back bug. See #fling() for

android/src/main/java/com/rnnestedscrollview/ReactNestedScrollViewManager.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
import android.annotation.TargetApi;
1111
import android.graphics.Color;
12-
import android.support.v4.view.ViewCompat;
12+
import androidx.core.view.ViewCompat;
1313
import android.util.DisplayMetrics;
1414

1515
import com.facebook.react.bridge.ReadableArray;
1616
import com.facebook.react.common.MapBuilder;
1717
import com.facebook.react.module.annotations.ReactModule;
18-
import com.facebook.react.uimanager.PixelUtil;
1918
import com.facebook.react.uimanager.DisplayMetricsHolder;
19+
import com.facebook.react.uimanager.PixelUtil;
2020
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
2121
import com.facebook.react.uimanager.Spacing;
2222
import com.facebook.react.uimanager.ThemedReactContext;
@@ -43,7 +43,6 @@
4343
* <p>Note that {@link ReactNestedScrollView} and {@link ReactHorizontalScrollView} are exposed to JS
4444
* as a single ScrollView component, configured via the {@code horizontal} boolean property.
4545
*/
46-
@TargetApi(11)
4746
@ReactModule(name = ReactNestedScrollViewManager.REACT_CLASS)
4847
public class ReactNestedScrollViewManager
4948
extends ViewGroupManager<ReactNestedScrollView>
@@ -105,6 +104,15 @@ public void setSnapToOffsets(ReactNestedScrollView view, @Nullable ReadableArray
105104
view.setSnapOffsets(offsets);
106105
}
107106

107+
@ReactProp(name = "snapToStart")
108+
public void setSnapToStart(ReactNestedScrollView view, boolean snapToStart) {
109+
view.setSnapToStart(snapToStart);
110+
}
111+
@ReactProp(name = "snapToEnd")
112+
public void setSnapToEnd(ReactNestedScrollView view, boolean snapToEnd) {
113+
view.setSnapToEnd(snapToEnd);
114+
}
115+
108116
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
109117
public void setRemoveClippedSubviews(ReactNestedScrollView view, boolean removeClippedSubviews) {
110118
view.setRemoveClippedSubviews(removeClippedSubviews);
@@ -135,6 +143,11 @@ public void setScrollPerfTag(ReactNestedScrollView view, @Nullable String scroll
135143
view.setScrollPerfTag(scrollPerfTag);
136144
}
137145

146+
@ReactProp(name = "pagingEnabled")
147+
public void setPagingEnabled(ReactNestedScrollView view, boolean pagingEnabled) {
148+
view.setPagingEnabled(pagingEnabled);
149+
}
150+
138151
/**
139152
* When set, fills the rest of the scrollview with a color to avoid setting a background and
140153
* creating unnecessary overdraw.
@@ -253,6 +266,11 @@ public void scrollToEnd(
253266
}
254267
}
255268

269+
@ReactProp(name = "persistentScrollbar")
270+
public void setPersistentScrollbar(ReactNestedScrollView view, boolean value) {
271+
view.setScrollbarFadingEnabled(!value);
272+
}
273+
256274
@Override
257275
public @Nullable Map<String, Object> getExportedCustomDirectEventTypeConstants() {
258276
return createExportedCustomDirectEventTypeConstants();

0 commit comments

Comments
 (0)