From a9d5a0c3b44d9cd6de4575ae5e5f5f768ee3b2cb Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Thu, 9 Mar 2017 22:01:15 -0800 Subject: [PATCH] native animated scroll event support Reviewed By: yungsters Differential Revision: D4648383 fbshipit-source-id: fdb8e2deaa06b2d2f9002cee2c0b827dbd7a5570 --- Examples/UIExplorer/js/FlatListExample.js | 42 ++++++++++++++++--- Libraries/CustomComponents/Lists/FlatList.js | 9 ++++ .../CustomComponents/Lists/VirtualizedList.js | 12 +++++- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Examples/UIExplorer/js/FlatListExample.js b/Examples/UIExplorer/js/FlatListExample.js index 9eae853bf92..90263d70aae 100644 --- a/Examples/UIExplorer/js/FlatListExample.js +++ b/Examples/UIExplorer/js/FlatListExample.js @@ -26,6 +26,7 @@ const React = require('react'); const ReactNative = require('react-native'); const { + Animated, FlatList, StyleSheet, View, @@ -47,6 +48,8 @@ const { renderSmallSwitchOption, } = require('./ListExampleShared'); +const AnimatedFlatList = Animated.createAnimatedComponent(FlatList); + const VIEWABILITY_CONFIG = { minimumViewTime: 3000, viewAreaCoveragePercentThreshold: 100, @@ -66,15 +69,29 @@ class FlatListExample extends React.PureComponent { logViewable: false, virtualized: true, }; + _onChangeFilterText = (filterText) => { this.setState({filterText}); }; + _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() { - this._listRef.recordInteraction(); // e.g. flipping logViewable switch + this._listRef.getNode().recordInteraction(); // e.g. flipping logViewable switch } + render() { const filterRegex = new RegExp(String(this.state.filterText), 'i'); const filter = (item) => ( @@ -95,7 +112,6 @@ class FlatListExample extends React.PureComponent { @@ -104,10 +120,19 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'fixedHeight')} {renderSmallSwitchOption(this, 'logViewable')} {renderSmallSwitchOption(this, 'debug')} + - { - this._listRef.recordInteraction(); + this._listRef.getNode().recordInteraction(); pressItem(this, key); }; _listRef: FlatList<*>; @@ -196,6 +222,12 @@ const styles = StyleSheet.create({ searchRow: { paddingHorizontal: 10, }, + spindicator: { + marginLeft: 'auto', + width: 2, + height: 16, + backgroundColor: 'darkgray', + }, }); module.exports = FlatListExample; diff --git a/Libraries/CustomComponents/Lists/FlatList.js b/Libraries/CustomComponents/Lists/FlatList.js index 354c6a5ff49..5912c1aa70c 100644 --- a/Libraries/CustomComponents/Lists/FlatList.js +++ b/Libraries/CustomComponents/Lists/FlatList.js @@ -34,6 +34,7 @@ const MetroListView = require('MetroListView'); // Used as a fallback legacy option const React = require('React'); +const ReactNative = require('ReactNative'); const View = require('View'); const VirtualizedList = require('VirtualizedList'); @@ -231,6 +232,14 @@ class FlatList extends React.PureComponent, vo this._listRef.recordInteraction(); } + getScrollableNode() { + if (this._listRef && this._listRef.getScrollableNode) { + return this._listRef.getScrollableNode(); + } else { + return ReactNative.findNodeHandle(this._listRef); + } + } + componentWillMount() { this._checkProps(this.props); } diff --git a/Libraries/CustomComponents/Lists/VirtualizedList.js b/Libraries/CustomComponents/Lists/VirtualizedList.js index 5adb1a6fab5..81da8b55774 100644 --- a/Libraries/CustomComponents/Lists/VirtualizedList.js +++ b/Libraries/CustomComponents/Lists/VirtualizedList.js @@ -34,6 +34,7 @@ const Batchinator = require('Batchinator'); const React = require('React'); +const ReactNative = require('ReactNative'); const RefreshControl = require('RefreshControl'); const ScrollView = require('ScrollView'); const View = require('View'); @@ -233,6 +234,14 @@ class VirtualizedList extends React.PureComponent { this._updateViewableItems(this.props.data); } + getScrollableNode() { + if (this._scrollRef && this._scrollRef.getScrollableNode) { + return this._scrollRef.getScrollableNode(); + } else { + return ReactNative.findNodeHandle(this._scrollRef); + } + } + static defaultProps = { disableVirtualization: false, getItem: (data: any, index: number) => data[index], @@ -289,7 +298,8 @@ class VirtualizedList extends React.PureComponent { super(props); invariant( !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._updateCellsToRender,