我们如何实现像this这样的网格。我查看了许多反应本机库,但仍在寻找它。我尝试了自定义网格视图,但是在没有更多数据时创建了一个问题。 请让我知道最佳方法。
答案 0 :(得分:1)
通过创建自定义组件,我设法为自己的项目做到了。
注意:在使用以下组件之前,请记住:
ScrollView
代替了FlatList
,因为在我的情况下这是不可行的。可能效率不高。lodash
,请确保安装该库。MyImage
的自定义子组件,该子组件可以根据需要处理加载和错误。您可以跳过并使用您的图片标签或其他任何标签。说明:
我创建了包含三个图像的单元格。共有3种类型的细胞。
我创建块,或者我们可以使用lodash
构成数组数组,该数组用作每一行的数据。每个小块或数组将有3个对象。
groupEveryNthRow = 3
意味着我将从0开始的每3行上都有一个带有大图像的单元格。
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)}
/>