import React, { useCallback } from "react"; import { View, StyleSheet, ScrollView, Dimensions, ActivityIndicator } from "react-native"; import { ThemedText } from "@/components/ThemedText"; interface CustomScrollViewProps { data: any[]; renderItem: ({ item, index }: { item: any; index: number }) => React.ReactNode; numColumns?: number; loading?: boolean; loadingMore?: boolean; error?: string | null; onEndReached?: () => void; loadMoreThreshold?: number; emptyMessage?: string; ListFooterComponent?: React.ComponentType | React.ReactElement | null; } const { width } = Dimensions.get("window"); const CustomScrollView: React.FC = ({ data, renderItem, numColumns = 1, loading = false, loadingMore = false, error = null, onEndReached, loadMoreThreshold = 200, emptyMessage = "暂无内容", ListFooterComponent, }) => { const ITEM_WIDTH = numColumns > 0 ? width / numColumns - 24 : width - 24; const handleScroll = useCallback( ({ nativeEvent }: { nativeEvent: any }) => { const { layoutMeasurement, contentOffset, contentSize } = nativeEvent; const isCloseToBottom = layoutMeasurement.height + contentOffset.y >= contentSize.height - loadMoreThreshold; if (isCloseToBottom && !loadingMore && onEndReached) { onEndReached(); } }, [onEndReached, loadingMore, loadMoreThreshold] ); const renderFooter = () => { if (ListFooterComponent) { if (React.isValidElement(ListFooterComponent)) { return ListFooterComponent; } else if (typeof ListFooterComponent === "function") { const Component = ListFooterComponent as React.ComponentType; return ; } return null; } if (loadingMore) { return ; } return null; }; if (loading) { return ( ); } if (error) { return ( {error} ); } if (data.length === 0) { return ( {emptyMessage} ); } return ( {data.length > 0 ? ( <> {/* Render content in a grid layout */} {Array.from({ length: Math.ceil(data.length / numColumns) }).map((_, rowIndex) => ( {data.slice(rowIndex * numColumns, (rowIndex + 1) * numColumns).map((item, index) => ( {renderItem({ item, index: rowIndex * numColumns + index })} ))} ))} {renderFooter()} ) : ( {emptyMessage} )} ); }; const styles = StyleSheet.create({ centerContainer: { flex: 1, paddingTop: 20, justifyContent: "center", alignItems: "center", }, listContent: { paddingHorizontal: 16, paddingBottom: 20, }, rowContainer: { flexDirection: "row", justifyContent: "flex-start", flexWrap: "wrap", }, itemContainer: { margin: 8, alignItems: "center", }, }); export default CustomScrollView;