Implement SnapToAlignment in ReactHorizontalScrollView

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
This commit is contained in:
David Vacca
2021-09-29 01:47:45 -07:00
committed by Facebook GitHub Bot
parent deec1db9fd
commit b12256394e
2 changed files with 74 additions and 1 deletions
@@ -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;
@@ -23,6 +26,7 @@ import android.view.FocusFinder;
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;
@@ -912,7 +916,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
}
// 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;
}
@@ -955,6 +959,36 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
}
}
}
} 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;