mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-01-12 22:50:10 +08:00
ScrollView snapToStart/snapToEnd
Summary: Added `snapToStart` and `snapToEnd` props to ScrollView which work together with `snapToOffsets` and determine whether the beginning and end of the list automatically count as snap offsets or not. If not, the list is allowed to free-scroll between its start/end and the first/last snap offset. Reviewed By: sahrens Differential Revision: D9442386 fbshipit-source-id: 47a5fdb20f884542434b01b1f0a486ed2b478c6e
This commit is contained in:
committed by
Facebook Github Bot
parent
fd744dd56c
commit
5f48d28119
@@ -68,6 +68,8 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
private int mSnapInterval = 0;
|
||||
private float mDecelerationRate = 0.985f;
|
||||
private @Nullable List<Integer> mSnapOffsets;
|
||||
private boolean mSnapToStart = true;
|
||||
private boolean mSnapToEnd = true;
|
||||
private ReactViewBackgroundManager mReactBackgroundManager;
|
||||
|
||||
public ReactHorizontalScrollView(Context context) {
|
||||
@@ -167,6 +169,14 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
mSnapOffsets = snapOffsets;
|
||||
}
|
||||
|
||||
public void setSnapToStart(boolean snapToStart) {
|
||||
mSnapToStart = snapToStart;
|
||||
}
|
||||
|
||||
public void setSnapToEnd(boolean snapToEnd) {
|
||||
mSnapToEnd = snapToEnd;
|
||||
}
|
||||
|
||||
public void flashScrollIndicators() {
|
||||
awakenScrollBars();
|
||||
}
|
||||
@@ -473,6 +483,8 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
int targetOffset = 0;
|
||||
int smallerOffset = 0;
|
||||
int largerOffset = maximumOffset;
|
||||
int firstOffset = 0;
|
||||
int lastOffset = maximumOffset;
|
||||
|
||||
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
|
||||
// no way to customize the scroll duration. So, we create a temporary OverScroller
|
||||
@@ -505,6 +517,9 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
|
||||
// get the nearest snap points to the target offset
|
||||
if (mSnapOffsets != null) {
|
||||
firstOffset = mSnapOffsets.get(0);
|
||||
lastOffset = mSnapOffsets.get(mSnapOffsets.size() - 1);
|
||||
|
||||
for (int i = 0; i < mSnapOffsets.size(); i ++) {
|
||||
int offset = mSnapOffsets.get(i);
|
||||
|
||||
@@ -532,10 +547,35 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
? smallerOffset
|
||||
: largerOffset;
|
||||
|
||||
// Chose the correct snap offset based on velocity
|
||||
if (velocityX > 0) {
|
||||
// if scrolling after the last snap offset and snapping to the
|
||||
// end of the list is disabled, then we allow free scrolling
|
||||
int currentOffset = getScrollX();
|
||||
if (isRTL) {
|
||||
currentOffset = maximumOffset - currentOffset;
|
||||
}
|
||||
if (!mSnapToEnd && targetOffset >= lastOffset) {
|
||||
if (currentOffset >= lastOffset) {
|
||||
// free scrolling
|
||||
} else {
|
||||
// snap to end
|
||||
targetOffset = lastOffset;
|
||||
}
|
||||
} else if (!mSnapToStart && targetOffset <= firstOffset) {
|
||||
if (currentOffset <= firstOffset) {
|
||||
// free scrolling
|
||||
} else {
|
||||
// snap to beginning
|
||||
targetOffset = firstOffset;
|
||||
}
|
||||
} else if (velocityX > 0) {
|
||||
// when snapping velocity can feel sluggish for slow swipes
|
||||
velocityX += (int) ((largerOffset - targetOffset) * 10.0);
|
||||
|
||||
targetOffset = largerOffset;
|
||||
} else if (velocityX < 0) {
|
||||
// when snapping velocity can feel sluggish for slow swipes
|
||||
velocityX -= (int) ((targetOffset - smallerOffset) * 10.0);
|
||||
|
||||
targetOffset = smallerOffset;
|
||||
} else {
|
||||
targetOffset = nearestOffset;
|
||||
|
||||
@@ -97,6 +97,16 @@ public class ReactHorizontalScrollViewManager
|
||||
view.setSnapOffsets(offsets);
|
||||
}
|
||||
|
||||
@ReactProp(name = "snapToStart")
|
||||
public void setSnapToStart(ReactHorizontalScrollView view, boolean snapToStart) {
|
||||
view.setSnapToStart(snapToStart);
|
||||
}
|
||||
|
||||
@ReactProp(name = "snapToEnd")
|
||||
public void setSnapToEnd(ReactHorizontalScrollView view, boolean snapToEnd) {
|
||||
view.setSnapToEnd(snapToEnd);
|
||||
}
|
||||
|
||||
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
||||
public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) {
|
||||
view.setRemoveClippedSubviews(removeClippedSubviews);
|
||||
|
||||
@@ -67,6 +67,8 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
private int mSnapInterval = 0;
|
||||
private float mDecelerationRate = 0.985f;
|
||||
private @Nullable List<Integer> mSnapOffsets;
|
||||
private boolean mSnapToStart = true;
|
||||
private boolean mSnapToEnd = true;
|
||||
private View mContentView;
|
||||
private ReactViewBackgroundManager mReactBackgroundManager;
|
||||
|
||||
@@ -155,6 +157,14 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
mSnapOffsets = snapOffsets;
|
||||
}
|
||||
|
||||
public void setSnapToStart(boolean snapToStart) {
|
||||
mSnapToStart = snapToStart;
|
||||
}
|
||||
|
||||
public void setSnapToEnd(boolean snapToEnd) {
|
||||
mSnapToEnd = snapToEnd;
|
||||
}
|
||||
|
||||
public void flashScrollIndicators() {
|
||||
awakenScrollBars();
|
||||
}
|
||||
@@ -441,6 +451,8 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
int targetOffset = 0;
|
||||
int smallerOffset = 0;
|
||||
int largerOffset = maximumOffset;
|
||||
int firstOffset = 0;
|
||||
int lastOffset = maximumOffset;
|
||||
|
||||
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
|
||||
// no way to customize the scroll duration. So, we create a temporary OverScroller
|
||||
@@ -466,6 +478,9 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
|
||||
// get the nearest snap points to the target offset
|
||||
if (mSnapOffsets != null) {
|
||||
firstOffset = mSnapOffsets.get(0);
|
||||
lastOffset = mSnapOffsets.get(mSnapOffsets.size() - 1);
|
||||
|
||||
for (int i = 0; i < mSnapOffsets.size(); i ++) {
|
||||
int offset = mSnapOffsets.get(i);
|
||||
|
||||
@@ -493,10 +508,31 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
? smallerOffset
|
||||
: largerOffset;
|
||||
|
||||
// Chose the correct snap offset based on velocity
|
||||
if (velocityY > 0) {
|
||||
// if scrolling after the last snap offset and snapping to the
|
||||
// end of the list is disabled, then we allow free scrolling
|
||||
if (!mSnapToEnd && targetOffset >= lastOffset) {
|
||||
if (getScrollY() >= lastOffset) {
|
||||
// free scrolling
|
||||
} else {
|
||||
// snap to end
|
||||
targetOffset = lastOffset;
|
||||
}
|
||||
} else if (!mSnapToStart && targetOffset <= firstOffset) {
|
||||
if (getScrollY() <= firstOffset) {
|
||||
// free scrolling
|
||||
} else {
|
||||
// snap to beginning
|
||||
targetOffset = firstOffset;
|
||||
}
|
||||
} else if (velocityY > 0) {
|
||||
// when snapping velocity can feel sluggish for slow swipes
|
||||
velocityY += (int) ((largerOffset - targetOffset) * 10.0);
|
||||
|
||||
targetOffset = largerOffset;
|
||||
} else if (velocityY < 0) {
|
||||
// when snapping velocity can feel sluggish for slow swipes
|
||||
velocityY -= (int) ((targetOffset - smallerOffset) * 10.0);
|
||||
|
||||
targetOffset = smallerOffset;
|
||||
} else {
|
||||
targetOffset = nearestOffset;
|
||||
|
||||
@@ -101,6 +101,16 @@ public class ReactScrollViewManager
|
||||
view.setSnapOffsets(offsets);
|
||||
}
|
||||
|
||||
@ReactProp(name = "snapToStart")
|
||||
public void setSnapToStart(ReactScrollView view, boolean snapToStart) {
|
||||
view.setSnapToStart(snapToStart);
|
||||
}
|
||||
|
||||
@ReactProp(name = "snapToEnd")
|
||||
public void setSnapToEnd(ReactScrollView view, boolean snapToEnd) {
|
||||
view.setSnapToEnd(snapToEnd);
|
||||
}
|
||||
|
||||
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
||||
public void setRemoveClippedSubviews(ReactScrollView view, boolean removeClippedSubviews) {
|
||||
view.setRemoveClippedSubviews(removeClippedSubviews);
|
||||
|
||||
Reference in New Issue
Block a user