Skip to content

Commit

Permalink
Implement SnapToAlignment in ReactHorizontalScrollView
Browse files Browse the repository at this point in the history
Summary:
This diff implements the SnapToAlignment functionality in ReactHorizontalScrollView 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 ReactHorizontalScrollView

Reviewed By: JoshuaGross

Differential Revision: D31174544

fbshipit-source-id: 204a82f55e3b7598124ce2528d8ad7d854c0ac77
  • Loading branch information
mdvacca authored and facebook-github-bot committed Sep 29, 2021
1 parent deec1db commit b122563
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

package com.facebook.react.views.scroll;

import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_CENTER;
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_DISABLED;
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_END;
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_START;

import android.animation.Animator;
import android.animation.ObjectAnimator;
Expand All @@ -23,6 +26,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.HorizontalScrollView;
import android.widget.OverScroller;
Expand Down Expand Up @@ -912,7 +916,7 @@ private void flingAndSnap(int velocityX) {
}

// pagingEnabled only allows snapping one interval at a time
if (mSnapInterval == 0 && mSnapOffsets == null) {
if (mSnapInterval == 0 && mSnapOffsets == null && mSnapToAlignment == SNAP_ALIGNMENT_DISABLED) {
smoothScrollAndSnap(velocityX);
return;
}
Expand Down Expand Up @@ -955,6 +959,36 @@ private void flingAndSnap(int velocityX) {
}
}
}
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED) {
ViewGroup contentView = (ViewGroup) getContentView();
for (int i = 1; i < contentView.getChildCount(); i++) {
View item = contentView.getChildAt(i);
int itemStartOffset;
switch (mSnapToAlignment) {
case SNAP_ALIGNMENT_CENTER:
itemStartOffset = item.getLeft() - (width - item.getWidth()) / 2;
break;
case SNAP_ALIGNMENT_START:
itemStartOffset = item.getLeft();
break;
case SNAP_ALIGNMENT_END:
itemStartOffset = item.getLeft() - (width - item.getWidth());
break;
default:
throw new IllegalStateException("");
}
if (itemStartOffset <= targetOffset) {
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
smallerOffset = itemStartOffset;
}
}

if (itemStartOffset >= targetOffset) {
if (itemStartOffset - targetOffset < largerOffset - targetOffset) {
largerOffset = itemStartOffset;
}
}
}
} else {
double interval = (double) getSnapInterval();
double ratio = (double) targetOffset / interval;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,45 @@ class ScrollViewSimpleExample extends React.Component<{...}> {
])}
</ScrollView>,
);
items.push(
<ScrollView
key={'scrollViewSnapStart'}
horizontal
snapToAlignment={'start'}
pagingEnabled>
{this.makeItems(NUM_ITEMS, [
styles.itemWrapper,
styles.horizontalItemWrapper,
styles.horizontalPagingItemWrapper,
])}
</ScrollView>,
);
items.push(
<ScrollView
key={'scrollViewSnapCenter'}
horizontal
snapToAlignment={'center'}
pagingEnabled>
{this.makeItems(NUM_ITEMS, [
styles.itemWrapper,
styles.horizontalItemWrapper,
styles.horizontalPagingItemWrapper,
])}
</ScrollView>,
);
items.push(
<ScrollView
key={'scrollViewSnapEnd'}
horizontal
snapToAlignment={'end'}
pagingEnabled>
{this.makeItems(NUM_ITEMS, [
styles.itemWrapper,
styles.horizontalItemWrapper,
styles.horizontalPagingItemWrapper,
])}
</ScrollView>,
);

const verticalScrollView = (
<ScrollView style={styles.verticalScrollView}>{items}</ScrollView>
Expand Down

0 comments on commit b122563

Please sign in to comment.