Skip to content

Commit 6941c4e

Browse files
nicklockwoodfacebook-github-bot-4
authored andcommitted
Replace ScrollView.scrollTo() API with something less ambiguous.
Summary: public The current `ScrollView.scrollTo()` API is confusing due to the `(y, x)` parameter order, and the boolean `animated` argument. E.g. ScrollView.scrollTo(5, 0, true) // what do these arguments mean? This diff replaces the API with a configuration object, so the arguments are all explicit: ScrollView.scrollTo({x: 0, y: 5, animated: true}) // much better The `scrollTo()` method checks the argument types, and provides backwards compatibility with the old argument format for now. Using the old API will generate a warning, and this will eventually be upgraded to an error. Reviewed By: davidaurelio Differential Revision: D2892287 fb-gh-sync-id: cec4d504242391267c6e863816b6180ced7a7d5e
1 parent 5f4390b commit 6941c4e

3 files changed

Lines changed: 89 additions & 26 deletions

File tree

Examples/UIExplorer/ScrollViewExample.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ var React = require('react-native');
1919
var {
2020
ScrollView,
2121
StyleSheet,
22+
Text,
23+
TouchableOpacity,
2224
View,
2325
Image
2426
} = React;
@@ -31,27 +33,45 @@ exports.examples = [
3133
title: '<ScrollView>',
3234
description: 'To make content scrollable, wrap it within a <ScrollView> component',
3335
render: function() {
36+
var _scrollView: ScrollView;
3437
return (
35-
<ScrollView
36-
automaticallyAdjustContentInsets={false}
37-
onScroll={() => { console.log('onScroll!'); }}
38-
scrollEventThrottle={200}
39-
style={styles.scrollView}>
40-
{THUMBS.map(createThumbRow)}
41-
</ScrollView>
38+
<View>
39+
<ScrollView
40+
ref={(scrollView) => { _scrollView = scrollView; }}
41+
automaticallyAdjustContentInsets={false}
42+
onScroll={() => { console.log('onScroll!'); }}
43+
scrollEventThrottle={200}
44+
style={styles.scrollView}>
45+
{THUMBS.map(createThumbRow)}
46+
</ScrollView>
47+
<TouchableOpacity
48+
style={styles.button}
49+
onPress={() => { _scrollView.scrollTo({y: 0}); }}>
50+
<Text>Scroll to top</Text>
51+
</TouchableOpacity>
52+
</View>
4253
);
4354
}
4455
}, {
4556
title: '<ScrollView> (horizontal = true)',
4657
description: 'You can display <ScrollView>\'s child components horizontally rather than vertically',
4758
render: function() {
59+
var _scrollView: ScrollView;
4860
return (
49-
<ScrollView
50-
automaticallyAdjustContentInsets={false}
51-
horizontal={true}
52-
style={[styles.scrollView, styles.horizontalScrollView]}>
53-
{THUMBS.map(createThumbRow)}
54-
</ScrollView>
61+
<View>
62+
<ScrollView
63+
ref={(scrollView) => { _scrollView = scrollView; }}
64+
automaticallyAdjustContentInsets={false}
65+
horizontal={true}
66+
style={[styles.scrollView, styles.horizontalScrollView]}>
67+
{THUMBS.map(createThumbRow)}
68+
</ScrollView>
69+
<TouchableOpacity
70+
style={styles.button}
71+
onPress={() => { _scrollView.scrollTo({x: 0}); }}>
72+
<Text>Scroll to start</Text>
73+
</TouchableOpacity>
74+
</View>
5575
);
5676
}
5777
}];

Libraries/Components/ScrollResponder.js

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,29 @@ var ScrollResponderMixin = {
349349

350350
/**
351351
* A helper function to scroll to a specific point in the scrollview.
352-
* This is currently used to help focus on child textviews, but this
353-
* can also be used to quickly scroll to any element we want to focus
352+
* This is currently used to help focus on child textviews, but can also
353+
* be used to quickly scroll to any element we want to focus. Syntax:
354+
*
355+
* scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
356+
*
357+
* Note: The weird argument signature is due to the fact that, for historical reasons,
358+
* the function also accepts separate arguments as as alternative to the options object.
359+
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
354360
*/
355-
scrollResponderScrollTo: function(offsetX: number, offsetY: number, animated: boolean = true) {
361+
scrollResponderScrollTo: function(
362+
x?: number | { x?: number; y?: number; animated?: boolean },
363+
y?: number,
364+
animated?: boolean
365+
) {
366+
if (typeof x === 'number') {
367+
console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.');
368+
} else {
369+
({x, y, animated} = x || {});
370+
}
356371
UIManager.dispatchViewManagerCommand(
357372
React.findNodeHandle(this),
358373
UIManager.RCTScrollView.Commands.scrollTo,
359-
[offsetX, offsetY, animated],
374+
[x || 0, y || 0, animated !== false],
360375
);
361376
},
362377

@@ -369,15 +384,24 @@ var ScrollResponderMixin = {
369384
},
370385

371386
/**
372-
* A helper function to zoom to a specific rect in the scrollview.
373-
* @param {object} rect Should have shape {x, y, width, height}
374-
* @param {bool} animated Specify whether zoom is instant or animated
387+
* A helper function to zoom to a specific rect in the scrollview. The argument has the shape
388+
* {x: number; y: number; width: number; height: number; animated: boolean = true}
389+
*
390+
* @platform ios
375391
*/
376-
scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }, animated: boolean = true) {
392+
scrollResponderZoomTo: function(
393+
rect: { x: number; y: number; width: number; height: number; animated?: boolean },
394+
animated?: boolean // deprecated, put this inside the rect argument instead
395+
) {
377396
if (Platform.OS === 'android') {
378397
invariant('zoomToRect is not implemented');
379398
} else {
380-
ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated);
399+
if ('animated' in rect) {
400+
var { animated, ...rect } = rect;
401+
} else if (typeof animated !== 'undefined') {
402+
console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead');
403+
}
404+
ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated !== false);
381405
}
382406
},
383407

Libraries/Components/ScrollView/ScrollView.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,17 +359,36 @@ var ScrollView = React.createClass({
359359
return React.findNodeHandle(this.refs[INNERVIEW]);
360360
},
361361

362-
scrollTo: function(destY: number = 0, destX: number = 0, animated: boolean = true) {
362+
/**
363+
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
364+
* Syntax:
365+
*
366+
* scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
367+
*
368+
* Note: The weird argument signature is due to the fact that, for historical reasons,
369+
* the function also accepts separate arguments as as alternative to the options object.
370+
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
371+
*/
372+
scrollTo: function(
373+
y?: number | { x?: number, y?: number, animated?: boolean },
374+
x?: number,
375+
animated?: boolean
376+
) {
377+
if (typeof y === 'number') {
378+
console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.');
379+
} else {
380+
({x, y, animated} = y || {});
381+
}
363382
// $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
364-
this.getScrollResponder().scrollResponderScrollTo(destX, destY, animated);
383+
this.getScrollResponder().scrollResponderScrollTo({x: x || 0, y: y || 0, animated: animated !== false});
365384
},
366385

367386
/**
368387
* Deprecated, do not use.
369388
*/
370-
scrollWithoutAnimationTo: function(destY: number = 0, destX: number = 0) {
389+
scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
371390
console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
372-
this.scrollTo(destX, destY, false);
391+
this.scrollTo({x, y, animated: false});
373392
},
374393

375394
handleScroll: function(e: Object) {

0 commit comments

Comments
 (0)