diff --git a/Examples/UIExplorer/ScrollViewExample.js b/Examples/UIExplorer/ScrollViewExample.js index 53d19148b..469c9a63c 100644 --- a/Examples/UIExplorer/ScrollViewExample.js +++ b/Examples/UIExplorer/ScrollViewExample.js @@ -19,6 +19,8 @@ var React = require('react-native'); var { ScrollView, StyleSheet, + Text, + TouchableOpacity, View, Image } = React; @@ -31,27 +33,45 @@ exports.examples = [ title: '', description: 'To make content scrollable, wrap it within a component', render: function() { + var _scrollView: ScrollView; return ( - { console.log('onScroll!'); }} - scrollEventThrottle={200} - style={styles.scrollView}> - {THUMBS.map(createThumbRow)} - + + { _scrollView = scrollView; }} + automaticallyAdjustContentInsets={false} + onScroll={() => { console.log('onScroll!'); }} + scrollEventThrottle={200} + style={styles.scrollView}> + {THUMBS.map(createThumbRow)} + + { _scrollView.scrollTo({y: 0}); }}> + Scroll to top + + ); } }, { title: ' (horizontal = true)', description: 'You can display \'s child components horizontally rather than vertically', render: function() { + var _scrollView: ScrollView; return ( - - {THUMBS.map(createThumbRow)} - + + { _scrollView = scrollView; }} + automaticallyAdjustContentInsets={false} + horizontal={true} + style={[styles.scrollView, styles.horizontalScrollView]}> + {THUMBS.map(createThumbRow)} + + { _scrollView.scrollTo({x: 0}); }}> + Scroll to start + + ); } }]; diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index e6ef4c554..65531aa2f 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -349,14 +349,29 @@ var ScrollResponderMixin = { /** * A helper function to scroll to a specific point in the scrollview. - * This is currently used to help focus on child textviews, but this - * can also be used to quickly scroll to any element we want to focus + * This is currently used to help focus on child textviews, but can also + * be used to quickly scroll to any element we want to focus. Syntax: + * + * scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true}) + * + * Note: The weird argument signature is due to the fact that, for historical reasons, + * the function also accepts separate arguments as as alternative to the options object. + * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. */ - scrollResponderScrollTo: function(offsetX: number, offsetY: number, animated: boolean = true) { + scrollResponderScrollTo: function( + x?: number | { x?: number; y?: number; animated?: boolean }, + y?: number, + animated?: boolean + ) { + if (typeof x === 'number') { + console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.'); + } else { + ({x, y, animated} = x || {}); + } UIManager.dispatchViewManagerCommand( React.findNodeHandle(this), UIManager.RCTScrollView.Commands.scrollTo, - [offsetX, offsetY, animated], + [x || 0, y || 0, animated !== false], ); }, @@ -369,15 +384,24 @@ var ScrollResponderMixin = { }, /** - * A helper function to zoom to a specific rect in the scrollview. - * @param {object} rect Should have shape {x, y, width, height} - * @param {bool} animated Specify whether zoom is instant or animated + * A helper function to zoom to a specific rect in the scrollview. The argument has the shape + * {x: number; y: number; width: number; height: number; animated: boolean = true} + * + * @platform ios */ - scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }, animated: boolean = true) { + scrollResponderZoomTo: function( + rect: { x: number; y: number; width: number; height: number; animated?: boolean }, + animated?: boolean // deprecated, put this inside the rect argument instead + ) { if (Platform.OS === 'android') { invariant('zoomToRect is not implemented'); } else { - ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated); + if ('animated' in rect) { + var { animated, ...rect } = rect; + } else if (typeof animated !== 'undefined') { + console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead'); + } + ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated !== false); } }, diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 623951b5e..279712808 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -359,17 +359,36 @@ var ScrollView = React.createClass({ return React.findNodeHandle(this.refs[INNERVIEW]); }, - scrollTo: function(destY: number = 0, destX: number = 0, animated: boolean = true) { + /** + * Scrolls to a given x, y offset, either immediately or with a smooth animation. + * Syntax: + * + * scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true}) + * + * Note: The weird argument signature is due to the fact that, for historical reasons, + * the function also accepts separate arguments as as alternative to the options object. + * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. + */ + scrollTo: function( + y?: number | { x?: number, y?: number, animated?: boolean }, + x?: number, + animated?: boolean + ) { + if (typeof y === 'number') { + console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.'); + } else { + ({x, y, animated} = y || {}); + } // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now - this.getScrollResponder().scrollResponderScrollTo(destX, destY, animated); + this.getScrollResponder().scrollResponderScrollTo({x: x || 0, y: y || 0, animated: animated !== false}); }, /** * Deprecated, do not use. */ - scrollWithoutAnimationTo: function(destY: number = 0, destX: number = 0) { + scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) { console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead'); - this.scrollTo(destX, destY, false); + this.scrollTo({x, y, animated: false}); }, handleScroll: function(e: Object) {