From 0090cfe03da71dbf5664a3bd50666c7cecd2c09f Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 22:10:36 +0300 Subject: [PATCH 01/12] Add initial implementation of horizontal snap --- .../views/scroll/ReactHorizontalScrollView.java | 14 +++++++++++++- .../scroll/ReactHorizontalScrollViewManager.java | 9 +++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index b8f6dfabd5d6a9..852acf1434d150 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -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); @@ -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); @@ -303,6 +308,13 @@ public void run() { postOnAnimationDelayed(mPostTouchRunnable, ReactScrollViewHelper.MOMENTUM_DELAY); } + private int getSnapInterval() { + if (mSnapInterval != 0) { + return mSnapInterval; + } + return getWidth(); + } + /** * This will smooth scroll us to the nearest page boundary * It currently just looks at where the content is relative to the page and slides to the nearest @@ -310,7 +322,7 @@ public void run() { * scrolling. */ private void smoothScrollToPage(int velocity) { - int width = getWidth(); + int width = getSnapInterval(); int currentX = getScrollX(); // TODO (t11123799) - Should we do anything beyond linear accounting of the velocity int predictedX = currentX + velocity; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index 24996edcf320e7..22e97dbd88e0b3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -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; @@ -68,6 +70,13 @@ public void setScrollEnabled(ReactHorizontalScrollView view, boolean value) { view.setScrollEnabled(value); } + @ReactProp(name = "snapToInterval") + public void setSnapToInterval(ReactHorizontalScrollView view, int snapToInterval) { + DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics(); + view.setSnapInterval((int)(snapToInterval * screenDisplayMetrics.density)); + } + + @ReactProp(name = "showsHorizontalScrollIndicator") public void setShowsHorizontalScrollIndicator(ReactHorizontalScrollView view, boolean value) { view.setHorizontalScrollBarEnabled(value); From 4942c3d9f6c977d6753011ecddb8b298dfc4a5ce Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 22:20:11 +0300 Subject: [PATCH 02/12] Refactor function to if statement --- .../react/views/scroll/ReactHorizontalScrollView.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 852acf1434d150..b7e5e7183759ae 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -308,13 +308,6 @@ public void run() { postOnAnimationDelayed(mPostTouchRunnable, ReactScrollViewHelper.MOMENTUM_DELAY); } - private int getSnapInterval() { - if (mSnapInterval != 0) { - return mSnapInterval; - } - return getWidth(); - } - /** * This will smooth scroll us to the nearest page boundary * It currently just looks at where the content is relative to the page and slides to the nearest @@ -322,7 +315,7 @@ private int getSnapInterval() { * scrolling. */ private void smoothScrollToPage(int velocity) { - int width = getSnapInterval(); + 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; From ac58c9aeb3c41984f5b0622ca8179c9de1b4e389 Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 22:31:29 +0300 Subject: [PATCH 03/12] Put paging on when snap is defined so JSX is the same on both platforms --- .../react/views/scroll/ReactHorizontalScrollViewManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index 22e97dbd88e0b3..c87afceb8d91c5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -72,6 +72,7 @@ public void setScrollEnabled(ReactHorizontalScrollView view, boolean 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)); } From f900ab3b276ca801d215a0542de50405f16b1d1d Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 22:55:19 +0300 Subject: [PATCH 04/12] Remove only iOS from docs --- Libraries/Components/ScrollView/ScrollView.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 66cce10ce3cafd..91aea2583a488b 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -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, /** From bd635e90ad2686a2ae10a5bcbfa7cdfb70206e91 Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:12:18 +0300 Subject: [PATCH 05/12] Refactor example to shorter --- RNTester/js/ScrollViewSimpleExample.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index f1e18563acc0c4..0d846b91d59ca7 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -39,21 +39,17 @@ class ScrollViewSimpleExample extends React.Component { }; render() { - // One of the items is a horizontal scroll view var items = this.makeItems(NUM_ITEMS, styles.itemWrapper); - items[4] = ( - - {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} - - ); - var verticalScrollView = ( + return ( - {items} + {items.map((item, index) => index === 4 ? ( + + {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} + + ) : item)} ); - - return verticalScrollView; } } From 77c9c73707086df3ef43ff945e61fd5d63d93ceb Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:13:46 +0300 Subject: [PATCH 06/12] Use shorter syntax --- RNTester/js/ScrollViewSimpleExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index 0d846b91d59ca7..7fcd125ae66516 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -44,7 +44,7 @@ class ScrollViewSimpleExample extends React.Component { return ( {items.map((item, index) => index === 4 ? ( - + {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} ) : item)} From 12b884b0c8756d19196d8e6af334d2913c169428 Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:24:56 +0300 Subject: [PATCH 07/12] Add snapToInterval to examples --- RNTester/js/ScrollViewSimpleExample.js | 37 +++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index 7fcd125ae66516..a72a39c85fe1f8 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -38,21 +38,44 @@ class ScrollViewSimpleExample extends React.Component { return items; }; + getListItem = (item, index) => { + if (index === 4) { + return ( + + {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} + + ); + } + else if (index === 5) { + return ( + + {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} + + ); + } + + return item; + } + render() { var items = this.makeItems(NUM_ITEMS, styles.itemWrapper); return ( - {items.map((item, index) => index === 4 ? ( - - {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} - - ) : item)} + {items.map(this.getListItem)} ); } } +const horizontalItemWidth = 125; +const itemMargin = 5; + var styles = StyleSheet.create({ verticalScrollView: { margin: 10, @@ -64,10 +87,10 @@ var styles = StyleSheet.create({ borderWidth: 5, borderColor: '#a52a2a', padding: 30, - margin: 5, + margin: itemMargin, }, horizontalItemWrapper: { - padding: 50 + width: horizontalItemWidth, } }); From d8083bbb515d77afa67265b8fe2d12e018cd1d6e Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:28:16 +0300 Subject: [PATCH 08/12] Remove paging and render less items --- RNTester/js/ScrollViewSimpleExample.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index a72a39c85fe1f8..ca10f9dd9cc874 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -42,7 +42,7 @@ class ScrollViewSimpleExample extends React.Component { if (index === 4) { return ( - {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} + {this.makeItems(10, [styles.itemWrapper, styles.horizontalItemWrapper])} ); } @@ -52,9 +52,8 @@ class ScrollViewSimpleExample extends React.Component { key="scrollViewSnap" horizontal snapToInterval={horizontalItemWidth + 2 * itemMargin} - pagingEnabled > - {this.makeItems(NUM_ITEMS, [styles.itemWrapper, styles.horizontalItemWrapper])} + {this.makeItems(10, [styles.itemWrapper, styles.horizontalItemWrapper])} ); } From 5503649cf92d14ea6f380201590ed79b5f894868 Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:33:03 +0300 Subject: [PATCH 09/12] Make element slighty bigger --- RNTester/js/ScrollViewSimpleExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index ca10f9dd9cc874..ac280948ca2fee 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -72,7 +72,7 @@ class ScrollViewSimpleExample extends React.Component { } } -const horizontalItemWidth = 125; +const horizontalItemWidth = 140; const itemMargin = 5; var styles = StyleSheet.create({ From fc1af45da9d698666542e859d8cb22492d0572af Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:39:28 +0300 Subject: [PATCH 10/12] Use always default styles for generated items --- RNTester/js/ScrollViewSimpleExample.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index ac280948ca2fee..ef7b51f96673d9 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -20,17 +20,15 @@ var { TouchableOpacity } = ReactNative; -var NUM_ITEMS = 20; - class ScrollViewSimpleExample extends React.Component { static title = ''; static description = 'Component that enables scrolling through child components.'; - makeItems = (nItems: number, styles): Array => { + makeItems = (nItems: number, extraStyle): Array => { var items = []; for (var i = 0; i < nItems; i++) { items[i] = ( - + {'Item ' + i} ); @@ -42,7 +40,7 @@ class ScrollViewSimpleExample extends React.Component { if (index === 4) { return ( - {this.makeItems(10, [styles.itemWrapper, styles.horizontalItemWrapper])} + {this.makeItems(10, styles.horizontalItemWrapper)} ); } @@ -53,7 +51,7 @@ class ScrollViewSimpleExample extends React.Component { horizontal snapToInterval={horizontalItemWidth + 2 * itemMargin} > - {this.makeItems(10, [styles.itemWrapper, styles.horizontalItemWrapper])} + {this.makeItems(10, styles.horizontalItemWrapper)} ); } @@ -62,11 +60,9 @@ class ScrollViewSimpleExample extends React.Component { } render() { - var items = this.makeItems(NUM_ITEMS, styles.itemWrapper); - return ( - {items.map(this.getListItem)} + {this.makeItems(20).map(this.getListItem)} ); } From 0a80ce183555bd8b58fa9c7b0f57c59de2fd052a Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Mon, 31 Jul 2017 23:40:54 +0300 Subject: [PATCH 11/12] Remove annoying TouchableOpacity that does not do anything --- RNTester/js/ScrollViewSimpleExample.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index ef7b51f96673d9..41a3fbd437d65c 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -17,7 +17,7 @@ var { ScrollView, StyleSheet, Text, - TouchableOpacity + View } = ReactNative; class ScrollViewSimpleExample extends React.Component { @@ -28,9 +28,9 @@ class ScrollViewSimpleExample extends React.Component { var items = []; for (var i = 0; i < nItems; i++) { items[i] = ( - + {'Item ' + i} - + ); } return items; From 254e1d95f48648dc23a662241af852236d2e0cc9 Mon Sep 17 00:00:00 2001 From: Henrik Raitasola Date: Tue, 1 Aug 2017 01:06:56 +0300 Subject: [PATCH 12/12] Add flow types --- RNTester/js/ScrollViewSimpleExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index 41a3fbd437d65c..df965434076699 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -36,7 +36,7 @@ class ScrollViewSimpleExample extends React.Component { return items; }; - getListItem = (item, index) => { + getListItem = (item: any, index: number) => { if (index === 4) { return (