Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ANDROID] Add snapToInterval support for horizontal ScrollView #15297

Closed
wants to merge 12 commits into from
6 changes: 2 additions & 4 deletions Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,9 @@ const ScrollView = createReactClass({
/**
* When set, causes the scroll view to stop at multiples of the value of
* `snapToInterval`. This can be used for paginating through children
* that have lengths smaller than the scroll view. Typically used in
* combination with `snapToAlignment` and `decelerationRate="fast"`.
* that have lengths smaller than the scroll view. When used on iOS it is typically combined
* with `snapToAlignment` and `decelerationRate="fast"`.
* Overrides less configurable `pagingEnabled` prop.
*
* @platform ios
*/
snapToInterval: PropTypes.number,
/**
Expand Down
54 changes: 34 additions & 20 deletions RNTester/js/ScrollViewSimpleExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,60 @@ var {
ScrollView,
StyleSheet,
Text,
TouchableOpacity
View
} = ReactNative;

var NUM_ITEMS = 20;

class ScrollViewSimpleExample extends React.Component {
static title = '<ScrollView>';
static description = 'Component that enables scrolling through child components.';

makeItems = (nItems: number, styles): Array<any> => {
makeItems = (nItems: number, extraStyle): Array<any> => {
var items = [];
for (var i = 0; i < nItems; i++) {
items[i] = (
<TouchableOpacity key={i} style={styles}>
<View key={i} style={[styles.itemWrapper, extraStyle]}>
<Text>{'Item ' + i}</Text>
</TouchableOpacity>
</View>
);
}
return items;
};

render() {
// One of the items is a horizontal scroll view
var items = this.makeItems(NUM_ITEMS, styles.itemWrapper);
items[4] = (
<ScrollView key={'scrollView'} horizontal={true}>
{this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])}
</ScrollView>
);
getListItem = (item: any, index: number) => {
if (index === 4) {
return (
<ScrollView key="scrollView" horizontal>
{this.makeItems(10, styles.horizontalItemWrapper)}
</ScrollView>
);
}
else if (index === 5) {
return (
<ScrollView
key="scrollViewSnap"
horizontal
snapToInterval={horizontalItemWidth + 2 * itemMargin}
>
{this.makeItems(10, styles.horizontalItemWrapper)}
</ScrollView>
);
}

var verticalScrollView = (
return item;
}

render() {
return (
<ScrollView style={styles.verticalScrollView}>
{items}
{this.makeItems(20).map(this.getListItem)}
</ScrollView>
);

return verticalScrollView;
}
}

const horizontalItemWidth = 140;
const itemMargin = 5;

var styles = StyleSheet.create({
verticalScrollView: {
margin: 10,
Expand All @@ -68,10 +82,10 @@ var styles = StyleSheet.create({
borderWidth: 5,
borderColor: '#a52a2a',
padding: 30,
margin: 5,
margin: itemMargin,
},
horizontalItemWrapper: {
padding: 50
width: horizontalItemWidth,
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
private @Nullable Drawable mEndBackground;
private int mEndFillColor = Color.TRANSPARENT;
private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable;
private int mSnapInterval = 0;

public ReactHorizontalScrollView(Context context) {
this(context, null);
Expand Down Expand Up @@ -92,6 +93,10 @@ public void setPagingEnabled(boolean pagingEnabled) {
mPagingEnabled = pagingEnabled;
}

public void setSnapInterval(int snapInterval) {
mSnapInterval = snapInterval;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec);
Expand Down Expand Up @@ -310,7 +315,7 @@ public void run() {
* scrolling.
*/
private void smoothScrollToPage(int velocity) {
int width = getWidth();
int width = mSnapInterval != 0 ? mSnapInterval : getWidth();
int currentX = getScrollX();
// TODO (t11123799) - Should we do anything beyond linear accounting of the velocity
int predictedX = currentX + velocity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

import android.graphics.Color;
import android.view.View;
import android.util.DisplayMetrics;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.Spacing;
Expand Down Expand Up @@ -68,6 +70,14 @@ public void setScrollEnabled(ReactHorizontalScrollView view, boolean value) {
view.setScrollEnabled(value);
}

@ReactProp(name = "snapToInterval")
public void setSnapToInterval(ReactHorizontalScrollView view, int snapToInterval) {
view.setPagingEnabled(snapToInterval > 0);
DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics();
view.setSnapInterval((int)(snapToInterval * screenDisplayMetrics.density));
}


@ReactProp(name = "showsHorizontalScrollIndicator")
public void setShowsHorizontalScrollIndicator(ReactHorizontalScrollView view, boolean value) {
view.setHorizontalScrollBarEnabled(value);
Expand Down