繁体   English   中英

像instagram一样反应原生网格

[英]React native grid like instagram

我们如何才能做到像电网这样 我查看了许多 react native 库,但仍在寻找它。 我尝试了自定义网格视图,但在没有更多数据时创建了一个问题。 请让我知道最好的方法。

通过创建自定义组件,我设法为我的项目做到了这一点。

注意:在使用以下组件之前,请记住:

  1. 我使用ScrollView而不是FlatList因为在我的情况下它不可行。 它可能没有那么高效。
  2. 我使用了外部库lodash请确保安装它。
  3. 这仅适用于 3 列图像,但您可以根据需要进行更改。
  4. 我有一个名为MyImage的自定义子组件,它根据我的需要处理加载和错误。 您可以跳过并使用您的图像标签或任何其他标签。

解释:

我创建了包含三个图像的单元格。 共有 3 种类型的细胞。

  1. 右侧大图。
  2. 左侧大图。
  3. 没有大图像的普通网格。

我创建块,或者我们可以使用lodash来创建数组数组,它​​用作每一行的数据。 每个小块或数组将有 3 个对象。

groupEveryNthRow = 3表示从 0 开始,每第三行都有一个带有大图像的单元格。

bigImageSide表示大图像应该出现在哪一侧。 我不断地从左到右改变。 您可以根据您的情况进行选择。

所有其他代码都是不言自明的。 如果您不了解其他任何内容,请告诉我。

代码

InstaGrid.js

 import React from 'react'; import { View, StyleSheet, Dimensions, ScrollView, ActivityIndicator, } from 'react-native'; var {width} = Dimensions.get('window'); import * as _ from 'lodash'; import MyImage from './MyImage'; const InstaGrid = ({ data, columns, onEndReachedThreshold, onEndReached, loading = false, onItemClick, }) => { const groupEveryNthRow = 3; const {mainContainer, groupedGridContainer} = styles; var currentRow = 0; const rowsArray = _.chunk(data, columns); var bigImageSide = 'right'; const renderGroupedItem = (row) => { const smallImage1 = row[0]; const smallImage2 = row[1]; const largeImage = row[2]; if (bigImageSide === 'right') { bigImageSide = 'left'; return ( <View style={{flexDirection: 'row'}}> <View style={groupedGridContainer}> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnail} sourceObj={smallImage1} onPress={() => { onItemClick(smallImage1); }} /> </View> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnail} sourceObj={smallImage2} onPress={() => { onItemClick(smallImage2); }} /> </View> </View> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnailLarge} sourceObj={largeImage} onPress={() => { onItemClick(largeImage); }} /> </View> </View> ); } else { bigImageSide = 'right'; return ( <View style={{flexDirection: 'row'}}> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnailLarge} sourceObj={largeImage} onPress={() => { onItemClick(largeImage); }} /> </View> <View style={groupedGridContainer}> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnail} sourceObj={smallImage1} onPress={() => { onItemClick(smallImage1); }} /> </View> <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnail} sourceObj={smallImage2} onPress={() => { onItemClick(smallImage2); }} /> </View> </View> </View> ); } }; const renderSingleItem = (item) => { return ( <View style={styles.gridStyle}> <MyImage style={styles.imageThumbnail} sourceObj={item} onPress={() => { onItemClick(item); }} /> </View> ); }; const renderCell = (row) => { if (row.length >= columns && currentRow % groupEveryNthRow === 0) { currentRow++; return <View>{renderGroupedItem(row)}</View>; } currentRow++; return ( <View style={{flexDirection: 'row'}}> {row.map((item) => { return renderSingleItem(item); })} </View> ); }; const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => { const paddingToBottom = 20; return ( layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom ); }; const renderFooter = () => { return ( <View style={{marginBottom: 16}}> <ActivityIndicator animating size="large" /> </View> ); }; return ( <ScrollView scrollEventThrottle={onEndReachedThreshold} onScroll={({nativeEvent}) => { if (isCloseToBottom(nativeEvent)) { onEndReached(); } }}> <View style={mainContainer}> {rowsArray.map((row) => { return renderCell(row); })} </View> {loading && renderFooter()} </ScrollView> ); }; const styles = StyleSheet.create({ mainContainer: { width: '100%', }, groupedGridContainer: { flexDirection: 'column', flexWrap: 'wrap', }, imageThumbnail: { height: width / 3 - 12, width: width / 3 - 12, resizeMode: 'stretch', alignSelf: 'flex-start', justifyContent: 'flex-start', }, imageThumbnailLarge: { height: width * 0.6 + 12, width: width * 0.6 + 12, marginLeft: 4, resizeMode: 'stretch', alignSelf: 'flex-start', justifyContent: 'flex-start', }, gridStyle: { margin: 4, }, }); export default InstaGrid;

MyImage.js

 import React, {useState} from 'react'; import { TouchableOpacity, Image, StyleSheet, ActivityIndicator, } from 'react-native'; const MyImage = ({style, sourceObj, onPress}) => { const [imageError, setImageError] = useState(false); const [loading, setLoading] = useState(true); return ( <TouchableOpacity onPress={onPress}> {imageError || !sourceObj.card_images ? ( <Image source={require('../images/userImage.jpg')} style={style} onLoadEnd={() => setLoading(false)} /> ) : ( <Image style={style} source={{uri: sourceObj.card_images.front_image}} onError={(e) => { setLoading(false); setImageError(true); }} onLoadEnd={() => setLoading(false)} /> )} {loading && ( <ActivityIndicator style={styles.activityIndicator} animating={loading} /> )} </TouchableOpacity> ); }; const styles = StyleSheet.create({ activityIndicator: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }, }); export default MyImage;

使用方法:只需

 <InstaGrid data={details} columns={3} loading={loading} onItemClick={(item) => { console.log('Got the Item:' + JSON.stringify(item)); }} onEndReachedThreshold={400} onEndReached={() => (offset !== -1 ? fetchData() : null)} />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM