问题描述
正如您在上图中看到的,有一个由两列组成的垂直列表。我开发了两个Flat List,因为我无法使用Flat List列选项在一行上设置不同高度的照片样式。
我希望两个平面图具有相同的滚动位置。
我包装了两个FlatList组件以同步滚动。但这里有一个问题。ScllView忽略无限滚动并一次调用所有分页对象。存在性能问题。
如何解决此问题?
这是我的组件代码
import React from 'react'; import { View, Platfrom, Text, StyleSheet, AsyncStorage, TouchableOpacity, Image, FlatList, Button, Dimensions, ScrollView, ListView } from 'react-native'; import Icon from 'react-native-vector-icons/FontAwesome'; import { NavigationActions } from 'react-navigation'; import { connect } from 'react-redux'; import moment from 'moment'; import * as settings from '../../config/settings'; import Menu from '../menu'; import headerStyles from '../../styles/common/header'; import textStyles from '../../styles/common/text'; import containerStyles from '../../styles/common/container'; import imageStyles from '../../styles/common/image'; import boxStyles from '../../styles/common/box'; import objectStyles from '../../styles/common/object'; import commonStyles from '../../styles/common/common'; import colorStyles from '../../styles/common/color'; const window = Dimensions.get('window'); const styles = StyleSheet.create({ listView: { paddingTop: 20, backgroundColor: '#FFFFFF', }, fullScreen: { flex: 1, marginBottom: 50, }, floatView: { position: 'absolute', width: '90%', marginLeft: '5%', height: 100, bottom: -50, }, }); const phoneWidth = Dimensions.get('window').width class PurchaseListScreen extends React.Component { static navigationOptions = ({ navigation }) => { const { params = {} } = navigation.state return { title: '?? ?? ??', headerStyle: headerStyles.header, headerTitleStyle: headerStyles.headerTitle, headerRight: <Icon name="bars" size={30} color="#333" onPress={() => { params.showModal() }} style={{ padding: 10 }} />, } } constructor(props) { super(props); this.state = { user_token: '', refreshing: false, isModalVisible: false, leftColumneData: [], rightColumneData: [], leftNextKey: '', rightNextKey: '', }; this.hideModal = this.hideModal.bind(this); } componentDidMount() { this.props.navigation.setParams({ showModal: this.showModal }); this.purchaseListService(); } showModal = () => this.setState({ isModalVisible: true }) hideModal = () => this.setState({ isModalVisible: false }) navigate1 = (item) => { console.log('click navigate1'); const navigate1 = NavigationActions.navigate({ routeName: "home", }); this.props.navigation.dispatch(navigate1); }; purchaseListService = async () => { if (this.props.isLoggedIn) { let user_info = await AsyncStorage.getItem('user_info'); get_user_token = JSON.parse(user_info).key; this.setState({ user_token: get_user_token }); const api_uri1 = settings.base_uri + 'purchase-product/odd/' const request1 = { method: 'GET', headers: { 'Authorization': 'Token ' + get_user_token, 'Accept': 'application/json', 'Content-Type': 'application/json', } } const api_uri2 = settings.base_uri + 'purchase-product/even/' const request2 = { method: 'GET', headers: { 'Authorization': 'Token ' + get_user_token, 'Accept': 'application/json', 'Content-Type': 'application/json', } } fetch(api_uri1, request1) .then(res => res.json()) .then(res => { this.setState({ leftColumneData: [...res.results], leftNextKey: res.next }) }) .catch((error) => { console.error(error); }) fetch(api_uri2, request2) .then(res => res.json()) .then(res => { this.setState({ rightColumneData: [...res.results], rightNextKey: res.next, }) }) .catch((error) => { console.error(error); }) } else { const api_uri1 = settings.base_uri + 'purchase-product/odd/' const request1 = { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } } const api_uri2 = settings.base_uri + 'purchase-product/even/' const request2 = { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } } fetch(api_uri1, request1) .then(res => res.json()) .then(res => { this.setState({ leftColumneData: [...res.results], leftNextKey: res.next, }) }) .catch((error) => { console.error(error); }) fetch(api_uri2, request2) .then(res => res.json()) .then(res => { this.setState({ rightColumneData: [...res.results], rightNextKey: res.next, }) }) .catch((error) => { console.error(error); }) } } onEndReachedService = () => { console.log('run onEndReachedService'); if (this.props.isLoggedIn && this.state.leftNextKey) { const api_uri1 = this.state.leftNextKey const request1 = { method: 'GET', headers: { 'Authorization': 'Token ' + this.state.user_token, 'Accept': 'application/json', 'Content-Type': 'application/json', } } const api_uri2 = this.state.rightNextKey const request2 = { method: 'GET', headers: { 'Authorization': 'Token ' + this.state.user_token, 'Accept': 'application/json', 'Content-Type': 'application/json', } } fetch(api_uri1, request1) .then(res => res.json()) .then(res => { this.setState({ leftColumneData: [...this.state.leftColumneData, ...res.results], leftNextKey: res.next }) }) .catch((error) => { console.error(error); }) fetch(api_uri2, request2) .then(res => res.json()) .then(res => { this.setState({ rightColumneData: [...this.state.rightColumneData, ...res.results], rightNextKey: res.next, }) }) .catch((error) => { console.error(error); }) } else if (!this.props.isLoggedIn && this.state.leftNextKey){ const api_uri1 = this.state.leftNextKey const request1 = { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } } const api_uri2 = this.state.rightNextKey const request2 = { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } } fetch(api_uri1, request1) .then(res => res.json()) .then(res => { console.log('update res1', res); this.setState({ leftColumneData: [...this.state.leftColumneData, ...res.results], leftNextKey: res.next, }) }) .catch((error) => { console.error(error); }) fetch(api_uri2, request2) .then(res => res.json()) .then(res => { console.log('update res2', res); this.setState({ rightColumneData: [...this.state.rightColumneData, ...res.results], rightNextKey: res.next, }) }) .catch((error) => { console.error(error); }) } } likeService = async (pk, column) => { let user_info = await AsyncStorage.getItem('user_info'); user_token = JSON.parse(user_info).key; const api_uri = settings.base_uri + 'purchase-product/' + pk + '/like/' var request = { method: 'POST', headers: { 'Authorization': 'Token ' + user_token, 'Accept': 'application/json', 'Content-Type': 'application/json', } }; fetch(api_uri, request) .then(res => { if(column=='left'){ var items = this.state.leftColumneData for (i=0; i<items.length; i++) { let item = items[i] if (item.id==pk) { item.is_liked = !item.is_liked items[i] = item; this.setState({ leftColumneData: items }) } } } else { var items = this.state.rightColumneData for (i = 0; i < items.length; i++) { let item = items[i] if (item.id == pk) { item.is_liked = !item.is_liked items[i] = item; this.setState({ rightColumneData: items }) } } } }) .catch((error) => { console.error(error); }); } renderLabel = (text) => { if (text) { return ( <View style={{ backgroundColor: 'red', paddingVertical: 2, marginLeft: 3, marginTop: 5, marginBottom: 8, paddingHorizontal: 4 }}> <Text style={{ color: 'white', fontSize: 9, fontWeight: '400' }}>{text}</Text> </View> ) } else { return ( <View style={{ paddingVertical: 2, marginTop: 5, marginBottom: 8, }}> </View> ) } } renderList = (item, column) => { return( <View> <View style={{ flex: 1, borderColor: 'rgb(136, 136, 136)', borderWidth: 1, marginLeft: 15, marginTop: 15, backgroundColor: 'white', }}> <TouchableOpacity onPress={()=>{}}> {item.is_vertical? <Image source={{ uri: item.first_thumbnail }} style={{ flex:1, height: 210 }}/> : <Image source={{ uri: item.first_thumbnail }} style={{ flex: 1, height: 130 }} /> } </TouchableOpacity> <View style={{ flex: 1 }}> <View style={{ flexDirection: 'row' }}> <TouchableOpacity style={{ flex: 4 }}> <Text style={{ fontSize: 14, fontWeight: '600', color: 'rgb(35, 31, 32)', marginTop: 10, marginLeft: 8 }}>{item.name}</Text> <Text style={{ fontSize: 12, fontWeight: '500', color: 'rgb(35, 31, 32)', marginLeft: 8, marginTop: 8 }}>{item.partner.biz_name}</Text> <View style={{ flexDirection: 'row', marginLeft: 6 }}> {this.renderLabel(item.product_type_str)} {this.renderLabel(item.city.name)} </View> </TouchableOpacity> <View style={{ flex: 1, marginTop: 10, marginRight: 2, alignItems: 'center' }}> {this.props.isLoggedIn ? <View> {item.is_liked ? <Icon name="heart" size={17} color="red" onPress={() => { this.likeService(item.id, column); }} /> : <Icon name="heart-o" size={17} color="red" onPress={() => { this.likeService(item.id, column); }} /> } </View> : <View> <Icon name="heart-o" size={17} color="red" onPress={() => { console.log('press heart', column); }} /> </View>} </View> </View> <View style={[ colorStyles.greenBackground, { flex: 1, borderTopWidth: 1, borderColor: 'rgb(136, 136, 136)', padding: 5, paddingRight: 10, }]}> <Text style={{ textAlign: 'right', fontSize: 14, fontWeight: '500', color: 'rgb(35, 31, 32)', }}> {(item.price).toString().replace(/B(?=(d{3})+(?!d))/g, ",")}? {item.id} </Text> </View> </View> </View> </View> ) } render() { return ( <View style={{ flex: 1 }}> <Menu hideModal={this.hideModal.bind(this)} isVisible={this.state.isModalVisible} navigation={this.props.navigation} /> <View style={{ flexDirection: 'row' }}> <FlatList style={{ flex: 1 }} showsVerticalScrollIndicator={false} initialNumToRender={20} onEndReachedThreshold={1} onEndReached={this.onEndReachedService} refreshing={this.state.refreshing} onRefresh={this.purchaseListService.bind(this)} data={this.state.leftColumneData} renderItem={({ item }) => this.renderList(item, column='left')} keyExtractor={(item) => item.id} /> <FlatList style={{ flex: 1, paddingRight: 15 }} showsVerticalScrollIndicator={false} refreshing={this.state.refreshing} onRefresh={this.purchaseListService.bind(this)} data={this.state.rightColumneData} renderItem={({ item }) => this.renderList(item, column='right')} keyExtractor={(item) => item.id} /> </View> </View> ) } } const mapStateToProps = state => ({ isLoggedIn: state.loginReducer.isLoggedIn }) const PurchaseList = connect(mapStateToProps, null)(PurchaseListScreen); export default PurchaseList;
推荐答案
您可以尝试使用此代码平行滚动两个平面。
<ScrollView contentContainerStyle={{flexDirection:"row"}}> <Flatlist ... scrollEnabled={false} /> <Flatlist ... scrollEnabled={false} /> </ScrollView>