Add support for flashScrollIndicators on iOS

Summary:
Flashing scroll indicators is a standard behavior on iOS to show the user there's more content.

Launch RNTester on iOS, go to the ScrollView section, tap the "Flash scroll indicators" button.
You'll see this:

![Flash scroll indicators](https://cloud.githubusercontent.com/assets/57791/26250919/ebea607a-3cab-11e7-96c6-27579cc809ab.gif)

I've exposed the method `flashScrollIndicators` on all scrolling components that were already exposing a `scrollToXXX` method so it's usable from those components using a ref.

Let me know what you think.
Closes https://github.com/facebook/react-native/pull/14058

Differential Revision: D5103239

Pulled By: shergin

fbshipit-source-id: caad8474fbe475065418d771b17e4ea9766ffcdc
This commit is contained in:
Jean Regisser 2017-06-06 13:00:30 -07:00 committed by Facebook Github Bot
parent 7ee8dd788f
commit 5114b61b5e
12 changed files with 83 additions and 0 deletions

View File

@ -465,6 +465,16 @@ var ScrollResponderMixin = {
ScrollViewManager.zoomToRect(this.scrollResponderGetScrollableNode(), rect, animated !== false);
},
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
scrollResponderFlashScrollIndicators: function() {
invariant(ScrollViewManager && ScrollViewManager.flashScrollIndicators, 'flashScrollIndicators is not implemented');
ScrollViewManager.flashScrollIndicators(this.scrollResponderGetScrollableNode());
},
/**
* This method should be used as the callback to onFocus in a TextInputs'
* parent view. Note that any module using this mixin needs to return

View File

@ -495,6 +495,15 @@ const ScrollView = React.createClass({
this.scrollTo({x, y, animated: false});
},
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
flashScrollIndicators: function() {
this.getScrollResponder().scrollResponderFlashScrollIndicators();
},
_getKeyForIndex: function(index, childArray) {
const child = childArray[index];
return child && child.key;

View File

@ -342,6 +342,15 @@ class FlatList<ItemT> extends React.PureComponent<DefaultProps, Props<ItemT>, vo
this._listRef.recordInteraction();
}
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
flashScrollIndicators() {
this._listRef.flashScrollIndicators();
}
/**
* Provides a handle to the underlying scroll responder.
*/

View File

@ -292,6 +292,17 @@ var ListView = React.createClass({
}
},
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
flashScrollIndicators: function() {
if (this._scrollComponent && this._scrollComponent.flashScrollIndicators) {
this._scrollComponent.flashScrollIndicators();
}
},
setNativeProps: function(props: Object) {
if (this._scrollComponent) {
this._scrollComponent.setNativeProps(props);

View File

@ -283,6 +283,16 @@ class SectionList<SectionT: SectionBase<any>>
listRef && listRef.recordInteraction();
}
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
flashScrollIndicators() {
const listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
listRef && listRef.flashScrollIndicators();
}
/**
* Provides a handle to the underlying scroll responder.
*/

View File

@ -260,6 +260,10 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
this._updateViewableItems(this.props.data);
}
flashScrollIndicators() {
this._scrollRef.flashScrollIndicators();
}
/**
* Provides a handle to the underlying scroll responder.
* Note that `this._scrollRef` might not be a `ScrollView`, so we

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -14,6 +14,7 @@
var React = require('react');
var ReactNative = require('react-native');
var {
Platform,
ScrollView,
StyleSheet,
Text,
@ -51,6 +52,13 @@ exports.examples = [
onPress={() => { _scrollView.scrollToEnd({animated: true}); }}>
<Text>Scroll to bottom</Text>
</TouchableOpacity>
{ Platform.OS === 'ios' ?
<TouchableOpacity
style={styles.button}
onPress={() => { _scrollView.flashScrollIndicators(); }}>
<Text>Flash scroll indicators</Text>
</TouchableOpacity>
: null }
</View>
);
}
@ -81,6 +89,13 @@ exports.examples = [
onPress={() => { _scrollView.scrollToEnd({animated: true}); }}>
<Text>Scroll to end</Text>
</TouchableOpacity>
{ Platform.OS === 'ios' ?
<TouchableOpacity
style={styles.button}
onPress={() => { _scrollView.flashScrollIndicators(); }}>
<Text>Flash scroll indicators</Text>
</TouchableOpacity>
: null }
</View>
);
}

View File

@ -178,4 +178,19 @@ RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag
}];
}
RCT_EXPORT_METHOD(flashScrollIndicators:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry){
RCTScrollView *view = viewRegistry[reactTag];
if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
return;
}
[view.scrollView flashScrollIndicators];
}];
}
@end