From 87bdcbde6ac7472461242d86d5a695747a0f9d9e Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Mon, 3 Apr 2017 18:36:31 -0700 Subject: [PATCH] propagate getScrollResponder, getScrollableNode Summary: so users can call `setNativeProps` and do more compositing. **Test Plan:** Added this to `onPress` of `SectionListExample` and `FlatListExample`: this._listRef.getNode().getScrollResponder().setNativeProps({scrollEnabled: false}); and saw scroll get disabled. Note the call to `getNode` because we are using the `Animated.createComponent` wrapper. Reviewed By: achen1, bvaughn Differential Revision: D4821711 fbshipit-source-id: 8d1f3dd7ccc646524f154721c5c7036620d57132 --- Libraries/Lists/FlatList.js | 14 +++++++--- Libraries/Lists/MetroListView.js | 3 +++ Libraries/Lists/SectionList.js | 32 ++++++++++++++++++++++- Libraries/Lists/VirtualizedList.js | 11 ++++++++ Libraries/Lists/VirtualizedSectionList.js | 9 ++++++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 1e2af8692..4e9cdb85f 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -13,7 +13,6 @@ 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'); @@ -297,11 +296,18 @@ class FlatList extends React.PureComponent, vo this._listRef.recordInteraction(); } + /** + * Provides a handle to the underlying scroll responder. + */ + getScrollResponder() { + if (this._listRef) { + return this._listRef.getScrollResponder(); + } + } + getScrollableNode() { - if (this._listRef && this._listRef.getScrollableNode) { + if (this._listRef) { return this._listRef.getScrollableNode(); - } else { - return ReactNative.findNodeHandle(this._listRef); } } diff --git a/Libraries/Lists/MetroListView.js b/Libraries/Lists/MetroListView.js index 150b27220..c96107877 100644 --- a/Libraries/Lists/MetroListView.js +++ b/Libraries/Lists/MetroListView.js @@ -67,6 +67,9 @@ class MetroListView extends React.Component { this.props.horizontal ? {x: offset, animated} : {y: offset, animated} ); } + getListRef() { + return this._listRef; + } static defaultProps: DefaultProps = { keyExtractor: (item, index) => item.key || index, renderScrollComponent: (props: Props) => { diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index a0cb06425..dd87a354e 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -194,10 +194,40 @@ class SectionList> props: Props; static defaultProps: DefaultProps = defaultProps; + /** + * Tells the list an interaction has occured, which should trigger viewability calculations, e.g. + * if `waitForInteractions` is true and the user has not scrolled. This is typically called by + * taps on items or by navigation actions. + */ + recordInteraction() { + const listRef = this._wrapperListRef && this._wrapperListRef.getListRef(); + listRef && listRef.recordInteraction(); + } + + /** + * Provides a handle to the underlying scroll responder. + */ + getScrollResponder() { + const listRef = this._wrapperListRef && this._wrapperListRef.getListRef(); + if (listRef) { + return listRef.getScrollResponder(); + } + } + + getScrollableNode() { + const listRef = this._wrapperListRef && this._wrapperListRef.getListRef(); + if (listRef) { + return listRef.getScrollableNode(); + } + } + render() { const List = this.props.legacyImplementation ? MetroListView : VirtualizedSectionList; - return ; + return ; } + + _wrapperListRef: MetroListView | VirtualizedSectionList<*>; + _captureRef = (ref) => { this._wrapperListRef = ref; }; } module.exports = SectionList; diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 8e3664503..6bbd7aef0 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -224,6 +224,17 @@ class VirtualizedList extends React.PureComponent { this._updateViewableItems(this.props.data); } + /** + * Provides a handle to the underlying scroll responder. + * Note that `this._scrollRef` might not be a `ScrollView`, so we + * need to check that it responds to `getScrollResponder` before calling it. + */ + getScrollResponder() { + if (this._scrollRef && this._scrollRef.getScrollResponder) { + return this._scrollRef.getScrollResponder(); + } + } + getScrollableNode() { if (this._scrollRef && this._scrollRef.getScrollableNode) { return this._scrollRef.getScrollableNode(); diff --git a/Libraries/Lists/VirtualizedSectionList.js b/Libraries/Lists/VirtualizedSectionList.js index 9d6752e48..fdf6110ff 100644 --- a/Libraries/Lists/VirtualizedSectionList.js +++ b/Libraries/Lists/VirtualizedSectionList.js @@ -119,6 +119,10 @@ class VirtualizedSectionList data: [], }; + getListRef(): VirtualizedList { + return this._listRef; + } + _keyExtractor = (item: Item, index: number) => { const info = this._subExtractor(index); return (info && info.key) || String(index); @@ -257,8 +261,11 @@ class VirtualizedSectionList } render() { - return ; + return ; } + + _listRef: VirtualizedList; + _captureRef = (ref) => { this._listRef = ref; }; } function getItem(sections: ?Array, index: number): ?Item {