native animated scroll event support

Reviewed By: yungsters

Differential Revision: D4648383

fbshipit-source-id: fdb8e2deaa06b2d2f9002cee2c0b827dbd7a5570
This commit is contained in:
Spencer Ahrens 2017-03-09 22:01:15 -08:00 committed by Facebook Github Bot
parent 28ed5eddf2
commit 5177a55314
3 changed files with 57 additions and 6 deletions

View File

@ -26,6 +26,7 @@
const React = require('react'); const React = require('react');
const ReactNative = require('react-native'); const ReactNative = require('react-native');
const { const {
Animated,
FlatList, FlatList,
StyleSheet, StyleSheet,
View, View,
@ -47,6 +48,8 @@ const {
renderSmallSwitchOption, renderSmallSwitchOption,
} = require('./ListExampleShared'); } = require('./ListExampleShared');
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const VIEWABILITY_CONFIG = { const VIEWABILITY_CONFIG = {
minimumViewTime: 3000, minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100, viewAreaCoveragePercentThreshold: 100,
@ -66,15 +69,29 @@ class FlatListExample extends React.PureComponent {
logViewable: false, logViewable: false,
virtualized: true, virtualized: true,
}; };
_onChangeFilterText = (filterText) => { _onChangeFilterText = (filterText) => {
this.setState({filterText}); this.setState({filterText});
}; };
_onChangeScrollToIndex = (text) => { _onChangeScrollToIndex = (text) => {
this._listRef.scrollToIndex({viewPosition: 0.5, index: Number(text)}); this._listRef.getNode().scrollToIndex({viewPosition: 0.5, index: Number(text)});
}; };
_scrollPos = new Animated.Value(0);
_scrollSinkX = Animated.event(
[{nativeEvent: { contentOffset: { x: this._scrollPos } }}],
{useNativeDriver: true},
);
_scrollSinkY = Animated.event(
[{nativeEvent: { contentOffset: { y: this._scrollPos } }}],
{useNativeDriver: true},
);
componentDidUpdate() { componentDidUpdate() {
this._listRef.recordInteraction(); // e.g. flipping logViewable switch this._listRef.getNode().recordInteraction(); // e.g. flipping logViewable switch
} }
render() { render() {
const filterRegex = new RegExp(String(this.state.filterText), 'i'); const filterRegex = new RegExp(String(this.state.filterText), 'i');
const filter = (item) => ( const filter = (item) => (
@ -95,7 +112,6 @@ class FlatListExample extends React.PureComponent {
<PlainInput <PlainInput
onChangeText={this._onChangeScrollToIndex} onChangeText={this._onChangeScrollToIndex}
placeholder="scrollToIndex..." placeholder="scrollToIndex..."
style={styles.searchTextInput}
/> />
</View> </View>
<View style={styles.options}> <View style={styles.options}>
@ -104,10 +120,19 @@ class FlatListExample extends React.PureComponent {
{renderSmallSwitchOption(this, 'fixedHeight')} {renderSmallSwitchOption(this, 'fixedHeight')}
{renderSmallSwitchOption(this, 'logViewable')} {renderSmallSwitchOption(this, 'logViewable')}
{renderSmallSwitchOption(this, 'debug')} {renderSmallSwitchOption(this, 'debug')}
<Animated.View style={[styles.spindicator, {
transform: [
{rotate: this._scrollPos.interpolate({
inputRange: [0, 5000],
outputRange: ['0deg', '360deg'],
extrapolate: 'extend',
})}
]
}]} />
</View> </View>
</View> </View>
<SeparatorComponent /> <SeparatorComponent />
<FlatList <AnimatedFlatList
HeaderComponent={HeaderComponent} HeaderComponent={HeaderComponent}
FooterComponent={FooterComponent} FooterComponent={FooterComponent}
SeparatorComponent={SeparatorComponent} SeparatorComponent={SeparatorComponent}
@ -125,6 +150,7 @@ class FlatListExample extends React.PureComponent {
legacyImplementation={false} legacyImplementation={false}
numColumns={1} numColumns={1}
onRefresh={this._onRefresh} onRefresh={this._onRefresh}
onScroll={this.state.horizontal ? this._scrollSinkX : this._scrollSinkY}
onViewableItemsChanged={this._onViewableItemsChanged} onViewableItemsChanged={this._onViewableItemsChanged}
ref={this._captureRef} ref={this._captureRef}
refreshing={false} refreshing={false}
@ -180,7 +206,7 @@ class FlatListExample extends React.PureComponent {
} }
}; };
_pressItem = (key: number) => { _pressItem = (key: number) => {
this._listRef.recordInteraction(); this._listRef.getNode().recordInteraction();
pressItem(this, key); pressItem(this, key);
}; };
_listRef: FlatList<*>; _listRef: FlatList<*>;
@ -196,6 +222,12 @@ const styles = StyleSheet.create({
searchRow: { searchRow: {
paddingHorizontal: 10, paddingHorizontal: 10,
}, },
spindicator: {
marginLeft: 'auto',
width: 2,
height: 16,
backgroundColor: 'darkgray',
},
}); });
module.exports = FlatListExample; module.exports = FlatListExample;

View File

@ -34,6 +34,7 @@
const MetroListView = require('MetroListView'); // Used as a fallback legacy option const MetroListView = require('MetroListView'); // Used as a fallback legacy option
const React = require('React'); const React = require('React');
const ReactNative = require('ReactNative');
const View = require('View'); const View = require('View');
const VirtualizedList = require('VirtualizedList'); const VirtualizedList = require('VirtualizedList');
@ -235,6 +236,14 @@ class FlatList<ItemT> extends React.PureComponent<DefaultProps, Props<ItemT>, vo
this._listRef.recordInteraction(); this._listRef.recordInteraction();
} }
getScrollableNode() {
if (this._listRef && this._listRef.getScrollableNode) {
return this._listRef.getScrollableNode();
} else {
return ReactNative.findNodeHandle(this._listRef);
}
}
componentWillMount() { componentWillMount() {
this._checkProps(this.props); this._checkProps(this.props);
} }

View File

@ -34,6 +34,7 @@
const Batchinator = require('Batchinator'); const Batchinator = require('Batchinator');
const React = require('React'); const React = require('React');
const ReactNative = require('ReactNative');
const RefreshControl = require('RefreshControl'); const RefreshControl = require('RefreshControl');
const ScrollView = require('ScrollView'); const ScrollView = require('ScrollView');
const View = require('View'); const View = require('View');
@ -237,6 +238,14 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
this._updateViewableItems(this.props.data); this._updateViewableItems(this.props.data);
} }
getScrollableNode() {
if (this._scrollRef && this._scrollRef.getScrollableNode) {
return this._scrollRef.getScrollableNode();
} else {
return ReactNative.findNodeHandle(this._scrollRef);
}
}
static defaultProps = { static defaultProps = {
disableVirtualization: false, disableVirtualization: false,
getItem: (data: any, index: number) => data[index], getItem: (data: any, index: number) => data[index],
@ -293,7 +302,8 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
super(props); super(props);
invariant( invariant(
!props.onScroll || !props.onScroll.__isNative, !props.onScroll || !props.onScroll.__isNative,
'VirtualizedList does not support AnimatedEvent with onScroll and useNativeDriver', 'Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent ' +
'to support native onScroll events with useNativeDriver',
); );
this._updateCellsToRenderBatcher = new Batchinator( this._updateCellsToRenderBatcher = new Batchinator(
this._updateCellsToRender, this._updateCellsToRender,