react-native/RNTester/js/FlatListExample.js
Yunyu Lin daa7c78055 Add FlatList and SectionList to Animated exports
Summary: There are several cases for creating an animated implementation of FlatList or SectionList (e.g. passing Animated.Event for onScroll with useNativeDriver enabled, see FlatListExample or SectionListExample), so we might as well add them to the exports.

Reviewed By: sahrens

Differential Revision: D8886446

fbshipit-source-id: 4b207500ea4d8d10de8c1b2639a5f492bc62e560
2018-07-17 22:35:28 -07:00

225 lines
6.3 KiB
JavaScript

/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const Alert = require('Alert');
const React = require('react');
const ReactNative = require('react-native');
const {Animated, StyleSheet, View} = ReactNative;
const RNTesterPage = require('./RNTesterPage');
const infoLog = require('infoLog');
const {
FooterComponent,
HeaderComponent,
ItemComponent,
ListEmptyComponent,
ItemSeparatorComponent,
PlainInput,
SeparatorComponent,
Spindicator,
genItemData,
getItemLayout,
pressItem,
renderSmallSwitchOption,
} = require('./ListExampleShared');
const VIEWABILITY_CONFIG = {
minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100,
waitForInteraction: true,
};
class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> {
static title = '<FlatList>';
static description = 'Performant, scrollable list of data.';
state = {
data: genItemData(100),
debug: false,
horizontal: false,
inverted: false,
filterText: '',
fixedHeight: true,
logViewable: false,
virtualized: true,
empty: false,
};
_onChangeFilterText = filterText => {
this.setState({filterText});
};
_onChangeScrollToIndex = 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.getNode().recordInteraction(); // e.g. flipping logViewable switch
}
render() {
const filterRegex = new RegExp(String(this.state.filterText), 'i');
const filter = item =>
filterRegex.test(item.text) || filterRegex.test(item.title);
const filteredData = this.state.data.filter(filter);
return (
<RNTesterPage noSpacer={true} noScroll={true}>
<View style={styles.container}>
<View style={styles.searchRow}>
<View style={styles.options}>
<PlainInput
onChangeText={this._onChangeFilterText}
placeholder="Search..."
value={this.state.filterText}
/>
<PlainInput
onChangeText={this._onChangeScrollToIndex}
placeholder="scrollToIndex..."
/>
</View>
<View style={styles.options}>
{renderSmallSwitchOption(this, 'virtualized')}
{renderSmallSwitchOption(this, 'horizontal')}
{renderSmallSwitchOption(this, 'fixedHeight')}
{renderSmallSwitchOption(this, 'log')}
{renderSmallSwitchOption(this, 'inverted')}
{renderSmallSwitchOption(this, 'empty')}
{renderSmallSwitchOption(this, 'debug')}
<Spindicator value={this._scrollPos} />
</View>
</View>
<SeparatorComponent />
<Animated.FlatList
ItemSeparatorComponent={ItemSeparatorComponent}
ListHeaderComponent={<HeaderComponent />}
ListFooterComponent={FooterComponent}
ListEmptyComponent={ListEmptyComponent}
data={this.state.empty ? [] : filteredData}
debug={this.state.debug}
disableVirtualization={!this.state.virtualized}
getItemLayout={
this.state.fixedHeight ? this._getItemLayout : undefined
}
horizontal={this.state.horizontal}
inverted={this.state.inverted}
key={
(this.state.horizontal ? 'h' : 'v') +
(this.state.fixedHeight ? 'f' : 'd')
}
keyboardShouldPersistTaps="always"
keyboardDismissMode="on-drag"
legacyImplementation={false}
numColumns={1}
onEndReached={this._onEndReached}
onRefresh={this._onRefresh}
onScroll={
this.state.horizontal ? this._scrollSinkX : this._scrollSinkY
}
onViewableItemsChanged={this._onViewableItemsChanged}
ref={this._captureRef}
refreshing={false}
renderItem={this._renderItemComponent}
contentContainerStyle={styles.list}
viewabilityConfig={VIEWABILITY_CONFIG}
/>
</View>
</RNTesterPage>
);
}
_captureRef = ref => {
this._listRef = ref;
};
_getItemLayout = (data: any, index: number) => {
return getItemLayout(data, index, this.state.horizontal);
};
_onEndReached = () => {
if (this.state.data.length >= 1000) {
return;
}
this.setState(state => ({
data: state.data.concat(genItemData(100, state.data.length)),
}));
};
_onRefresh = () => Alert.alert('onRefresh: nothing to refresh :P');
_renderItemComponent = ({item, separators}) => {
return (
<ItemComponent
item={item}
horizontal={this.state.horizontal}
fixedHeight={this.state.fixedHeight}
onPress={this._pressItem}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
/>
);
};
// This is called when items change viewability by scrolling into or out of
// the viewable area.
_onViewableItemsChanged = (info: {
changed: Array<{
key: string,
isViewable: boolean,
item: any,
index: ?number,
section?: any,
}>,
}) => {
// Impressions can be logged here
if (this.state.logViewable) {
infoLog(
'onViewableItemsChanged: ',
info.changed.map(v => ({...v, item: '...'})),
);
}
};
_pressItem = (key: string) => {
this._listRef.getNode().recordInteraction();
pressItem(this, key);
};
_listRef: Animated.FlatList;
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'rgb(239, 239, 244)',
flex: 1,
},
list: {
backgroundColor: 'white',
flexGrow: 1,
},
options: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
},
searchRow: {
paddingHorizontal: 10,
},
});
module.exports = FlatListExample;