Skip to content

Commit e774c03

Browse files
mdvaccafacebook-github-bot
authored andcommitted
Implement snapToAlignment in vertical ScrollView
Summary: This diff implements the SnapToAlignment functionality in ReactScrollView for RN Android. In order to use SnapToAlignment, the pagingEnabled prop should be set Based on the documentation the behavior implemented in this diff is more "advanced" than the one implemendted in RNiOS, because it let you snap without specifying any interval nor offset (it calculates the intervals in real time based on the size of its content) I still need to verify how different RNiOS and RN Android behaviors are changelog: [Android][Added] Implement SnapToAlignment in ReactScrollView Reviewed By: JoshuaGross Differential Revision: D31182786 fbshipit-source-id: a9b55d9c00326ae21ca9b89575e79c60bf9edcca
1 parent c6e5640 commit e774c03

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ private void flingAndSnap(int velocityX) {
975975
itemStartOffset = item.getLeft() - (width - item.getWidth());
976976
break;
977977
default:
978-
throw new IllegalStateException("");
978+
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
979979
}
980980
if (itemStartOffset <= targetOffset) {
981981
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java

+39-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
package com.facebook.react.views.scroll;
99

10+
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_CENTER;
1011
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_DISABLED;
12+
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_END;
13+
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_START;
1114

1215
import android.animation.Animator;
1316
import android.animation.ObjectAnimator;
@@ -641,6 +644,10 @@ private int predictFinalScrollPosition(int velocityY) {
641644
return scroller.getFinalY();
642645
}
643646

647+
private View getContentView() {
648+
return getChildAt(0);
649+
}
650+
644651
/**
645652
* This will smooth scroll us to the nearest snap offset point It currently just looks at where
646653
* the content is and slides to the nearest point. It is intended to be run after we are done
@@ -697,7 +704,7 @@ private void flingAndSnap(int velocityY) {
697704
}
698705

699706
// pagingEnabled only allows snapping one interval at a time
700-
if (mSnapInterval == 0 && mSnapOffsets == null) {
707+
if (mSnapInterval == 0 && mSnapOffsets == null && mSnapToAlignment == SNAP_ALIGNMENT_DISABLED) {
701708
smoothScrollAndSnap(velocityY);
702709
return;
703710
}
@@ -734,6 +741,37 @@ private void flingAndSnap(int velocityY) {
734741
}
735742
}
736743
}
744+
745+
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED) {
746+
ViewGroup contentView = (ViewGroup) getContentView();
747+
for (int i = 1; i < contentView.getChildCount(); i++) {
748+
View item = contentView.getChildAt(i);
749+
int itemStartOffset;
750+
switch (mSnapToAlignment) {
751+
case SNAP_ALIGNMENT_CENTER:
752+
itemStartOffset = item.getTop() - (height - item.getHeight()) / 2;
753+
break;
754+
case SNAP_ALIGNMENT_START:
755+
itemStartOffset = item.getTop();
756+
break;
757+
case SNAP_ALIGNMENT_END:
758+
itemStartOffset = item.getTop() - (height - item.getHeight());
759+
break;
760+
default:
761+
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
762+
}
763+
if (itemStartOffset <= targetOffset) {
764+
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
765+
smallerOffset = itemStartOffset;
766+
}
767+
}
768+
769+
if (itemStartOffset >= targetOffset) {
770+
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
771+
largerOffset = itemStartOffset;
772+
}
773+
}
774+
}
737775
} else {
738776
double interval = (double) getSnapInterval();
739777
double ratio = (double) targetOffset / interval;

0 commit comments

Comments
 (0)