/** * 响应式网格布局组件 * 根据断点自动调整列数,支持间距配置 */ import React, { useMemo } from 'react'; import { View, StyleProp, ViewStyle, StyleSheet, Dimensions, } from 'react-native'; import { useResponsive, useColumnCount, useResponsiveSpacing, FineBreakpointKey, } from '../../hooks/useResponsive'; export interface ResponsiveGridProps { /** 子元素 */ children: React.ReactNode[]; /** 自定义样式 */ style?: StyleProp; /** 容器样式 */ containerStyle?: StyleProp; /** 项目样式 */ itemStyle?: StyleProp; /** 列数配置,根据断点设置 */ columns?: Partial>; /** 间距配置 */ gap?: Partial>; /** 行间距(默认等于 gap) */ rowGap?: Partial>; /** 列间距(默认等于 gap) */ columnGap?: Partial>; /** 是否启用等宽列 */ equalColumns?: boolean; /** 自定义列宽计算函数 */ getColumnWidth?: (containerWidth: number, columns: number, gap: number) => number; /** 渲染空状态 */ renderEmpty?: () => React.ReactNode; /** key 提取函数 */ keyExtractor?: (item: React.ReactNode, index: number) => string; } /** * 响应式网格布局组件 * * 根据屏幕宽度自动调整列数,支持平板/桌面端的多列布局 * * @example * * {items.map(item => )} * */ export function ResponsiveGrid({ children, style, containerStyle, itemStyle, columns: columnsConfig, gap: gapConfig, rowGap: rowGapConfig, columnGap: columnGapConfig, equalColumns = true, getColumnWidth, renderEmpty, keyExtractor, }: ResponsiveGridProps) { const { width } = useResponsive(); const columns = useColumnCount(columnsConfig); const defaultGap = useResponsiveSpacing(gapConfig); const rowGap = useResponsiveSpacing(rowGapConfig ?? gapConfig); const columnGap = useResponsiveSpacing(columnGapConfig ?? gapConfig); // 计算列宽 const columnWidth = useMemo(() => { if (getColumnWidth) { return getColumnWidth(width, columns, columnGap); } if (equalColumns) { // 等宽列计算:(总宽度 - (列数 - 1) * 列间距) / 列数 return (width - (columns - 1) * columnGap) / columns; } return undefined; }, [width, columns, columnGap, equalColumns, getColumnWidth]); // 将子元素分组为行 const rows = useMemo(() => { const items = React.Children.toArray(children); if (items.length === 0) return []; const result: React.ReactNode[][] = []; for (let i = 0; i < items.length; i += columns) { result.push(items.slice(i, i + columns)); } return result; }, [children, columns]); // 空状态处理 if (rows.length === 0 && renderEmpty) { return ( {renderEmpty()} ); } return ( {rows.map((row, rowIndex) => ( {row.map((child, colIndex) => { const index = rowIndex * columns + colIndex; const key = keyExtractor?.(child, index) ?? `grid-item-${index}`; return ( {child} ); })} ))} ); } const styles = StyleSheet.create({ container: { width: '100%', }, row: { flexDirection: 'row', alignItems: 'flex-start', }, item: { flexShrink: 0, }, }); export default ResponsiveGrid;