Skip to content

Commit 04184ef

Browse files
mdvaccafacebook-github-bot
authored andcommitted
Extend ScrollView.snapToAlignments in RN Android to reach feature parity with RN iOS
Summary: This diff extends the current implementation of ScrollView.snapToAlignments from RN Android to reach feature parity with RNiOS changelog: [Android][Changed] Implement ScrollView.snapToAlignments in RN Android Reviewed By: javache Differential Revision: D31206398 fbshipit-source-id: b6534965c476a0a4745ac98b419cbe05dc5c746e
1 parent e774c03 commit 04184ef

File tree

2 files changed

+115
-49
lines changed

2 files changed

+115
-49
lines changed

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

+52-25
Original file line numberDiff line numberDiff line change
@@ -960,37 +960,45 @@ private void flingAndSnap(int velocityX) {
960960
}
961961
}
962962
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED) {
963-
ViewGroup contentView = (ViewGroup) getContentView();
964-
for (int i = 1; i < contentView.getChildCount(); i++) {
965-
View item = contentView.getChildAt(i);
966-
int itemStartOffset;
967-
switch (mSnapToAlignment) {
968-
case SNAP_ALIGNMENT_CENTER:
969-
itemStartOffset = item.getLeft() - (width - item.getWidth()) / 2;
970-
break;
971-
case SNAP_ALIGNMENT_START:
972-
itemStartOffset = item.getLeft();
973-
break;
974-
case SNAP_ALIGNMENT_END:
975-
itemStartOffset = item.getLeft() - (width - item.getWidth());
976-
break;
977-
default:
978-
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
979-
}
980-
if (itemStartOffset <= targetOffset) {
981-
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
982-
smallerOffset = itemStartOffset;
963+
if (mSnapInterval > 0) {
964+
double ratio = (double) targetOffset / mSnapInterval;
965+
smallerOffset =
966+
Math.max(
967+
getItemStartOffset(
968+
mSnapToAlignment,
969+
(int) (Math.floor(ratio) * mSnapInterval),
970+
mSnapInterval,
971+
width),
972+
0);
973+
largerOffset =
974+
Math.min(
975+
getItemStartOffset(
976+
mSnapToAlignment,
977+
(int) (Math.ceil(ratio) * mSnapInterval),
978+
mSnapInterval,
979+
width),
980+
maximumOffset);
981+
} else {
982+
ViewGroup contentView = (ViewGroup) getContentView();
983+
for (int i = 1; i < contentView.getChildCount(); i++) {
984+
View item = contentView.getChildAt(i);
985+
int itemStartOffset =
986+
getItemStartOffset(mSnapToAlignment, item.getLeft(), item.getWidth(), width);
987+
if (itemStartOffset <= targetOffset) {
988+
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
989+
smallerOffset = itemStartOffset;
990+
}
983991
}
984-
}
985992

986-
if (itemStartOffset >= targetOffset) {
987-
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
988-
largerOffset = itemStartOffset;
993+
if (itemStartOffset >= targetOffset) {
994+
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
995+
largerOffset = itemStartOffset;
996+
}
989997
}
990998
}
991999
}
9921000
} else {
993-
double interval = (double) getSnapInterval();
1001+
double interval = getSnapInterval();
9941002
double ratio = (double) targetOffset / interval;
9951003
smallerOffset = (int) (Math.floor(ratio) * interval);
9961004
largerOffset = Math.min((int) (Math.ceil(ratio) * interval), maximumOffset);
@@ -1073,6 +1081,25 @@ private void flingAndSnap(int velocityX) {
10731081
}
10741082
}
10751083

1084+
private int getItemStartOffset(
1085+
int snapToAlignment, int itemStartPosition, int itemWidth, int viewPortWidth) {
1086+
int itemStartOffset;
1087+
switch (snapToAlignment) {
1088+
case SNAP_ALIGNMENT_CENTER:
1089+
itemStartOffset = itemStartPosition - (viewPortWidth - itemWidth) / 2;
1090+
break;
1091+
case SNAP_ALIGNMENT_START:
1092+
itemStartOffset = itemStartPosition;
1093+
break;
1094+
case SNAP_ALIGNMENT_END:
1095+
itemStartOffset = itemStartPosition - (viewPortWidth - itemWidth);
1096+
break;
1097+
default:
1098+
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
1099+
}
1100+
return itemStartOffset;
1101+
}
1102+
10761103
private void smoothScrollToNextPage(int direction) {
10771104
if (DEBUG_MODE) {
10781105
FLog.i(TAG, "smoothScrollToNextPage[%d] direction %d", getId(), direction);

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

+63-24
Original file line numberDiff line numberDiff line change
@@ -743,32 +743,52 @@ private void flingAndSnap(int velocityY) {
743743
}
744744

745745
} 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;
746+
if (mSnapInterval > 0) {
747+
double ratio = (double) targetOffset / mSnapInterval;
748+
smallerOffset =
749+
Math.max(
750+
getItemStartOffset(
751+
mSnapToAlignment,
752+
(int) (Math.floor(ratio) * mSnapInterval),
753+
mSnapInterval,
754+
height),
755+
0);
756+
largerOffset =
757+
Math.min(
758+
getItemStartOffset(
759+
mSnapToAlignment,
760+
(int) (Math.ceil(ratio) * mSnapInterval),
761+
mSnapInterval,
762+
height),
763+
maximumOffset);
764+
} else {
765+
ViewGroup contentView = (ViewGroup) getContentView();
766+
for (int i = 1; i < contentView.getChildCount(); i++) {
767+
View item = contentView.getChildAt(i);
768+
int itemStartOffset;
769+
switch (mSnapToAlignment) {
770+
case SNAP_ALIGNMENT_CENTER:
771+
itemStartOffset = item.getTop() - (height - item.getHeight()) / 2;
772+
break;
773+
case SNAP_ALIGNMENT_START:
774+
itemStartOffset = item.getTop();
775+
break;
776+
case SNAP_ALIGNMENT_END:
777+
itemStartOffset = item.getTop() - (height - item.getHeight());
778+
break;
779+
default:
780+
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
781+
}
782+
if (itemStartOffset <= targetOffset) {
783+
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
784+
smallerOffset = itemStartOffset;
785+
}
766786
}
767-
}
768787

769-
if (itemStartOffset >= targetOffset) {
770-
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
771-
largerOffset = itemStartOffset;
788+
if (itemStartOffset >= targetOffset) {
789+
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
790+
largerOffset = itemStartOffset;
791+
}
772792
}
773793
}
774794
}
@@ -847,6 +867,25 @@ private void flingAndSnap(int velocityY) {
847867
}
848868
}
849869

870+
private int getItemStartOffset(
871+
int snapToAlignment, int itemStartPosition, int itemHeight, int viewPortHeight) {
872+
int itemStartOffset;
873+
switch (snapToAlignment) {
874+
case SNAP_ALIGNMENT_CENTER:
875+
itemStartOffset = itemStartPosition - (viewPortHeight - itemHeight) / 2;
876+
break;
877+
case SNAP_ALIGNMENT_START:
878+
itemStartOffset = itemStartPosition;
879+
break;
880+
case SNAP_ALIGNMENT_END:
881+
itemStartOffset = itemStartPosition - (viewPortHeight - itemHeight);
882+
break;
883+
default:
884+
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
885+
}
886+
return itemStartOffset;
887+
}
888+
850889
private int getSnapInterval() {
851890
if (mSnapInterval != 0) {
852891
return mSnapInterval;

0 commit comments

Comments
 (0)