Skip to content

Commit

Permalink
Implement snapToAlignment in vertical ScrollView
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mdvacca authored and facebook-github-bot committed Sep 29, 2021
1 parent c6e5640 commit e774c03
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ private void flingAndSnap(int velocityX) {
itemStartOffset = item.getLeft() - (width - item.getWidth());
break;
default:
throw new IllegalStateException("");
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
}
if (itemStartOffset <= targetOffset) {
if (targetOffset - itemStartOffset < targetOffset - smallerOffset) {
Expand Down
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 Down Expand Up @@ -641,6 +644,10 @@ private int predictFinalScrollPosition(int velocityY) {
return scroller.getFinalY();
}

private View getContentView() {
return getChildAt(0);
}

/**
* This will smooth scroll us to the nearest snap offset point It currently just looks at where
* the content is and slides to the nearest point. It is intended to be run after we are done
Expand Down Expand Up @@ -697,7 +704,7 @@ private void flingAndSnap(int velocityY) {
}

// pagingEnabled only allows snapping one interval at a time
if (mSnapInterval == 0 && mSnapOffsets == null) {
if (mSnapInterval == 0 && mSnapOffsets == null && mSnapToAlignment == SNAP_ALIGNMENT_DISABLED) {
smoothScrollAndSnap(velocityY);
return;
}
Expand Down Expand Up @@ -734,6 +741,37 @@ private void flingAndSnap(int velocityY) {
}
}
}

} 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.getTop() - (height - item.getHeight()) / 2;
break;
case SNAP_ALIGNMENT_START:
itemStartOffset = item.getTop();
break;
case SNAP_ALIGNMENT_END:
itemStartOffset = item.getTop() - (height - item.getHeight());
break;
default:
throw new IllegalStateException("Invalid SnapToAlignment value: " + mSnapToAlignment);
}
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

0 comments on commit e774c03

Please sign in to comment.