React Native填字游戏棋盘实现方案咨询及优化建议
React Native填字游戏棋盘实现建议
先优化你的数据结构
你当前的position用(0,0)在JS里会被解析成表达式,建议改成数组[0,0];另外across/down用对象存储虽然可行,但后续遍历生成矩阵时不如数组方便,可以调整为数组结构:
const crosswordData = { across: [ { id: 1, question: "test", answer: "test", position: [0, 0], length: 4, } ], down: [] };
放弃FlatList,用嵌套View/ScrollView实现棋盘
FlatList更适合线性长列表,填字游戏是二维结构,用嵌套的行+列View更直观,索引处理也简单:
1. 自动生成棋盘矩阵
不用手动维护矩阵,根据单词数据自动生成包含黑格(0)、白格(1)、起始格(2)的矩阵:
// 计算棋盘最大行列数 const calculateBoardSize = (data) => { let maxRow = 0; let maxCol = 0; [...data.across, ...data.down].forEach(word => { const [row, col] = word.position; // 从across/down判断单词方向 if (data.across.includes(word)) { maxCol = Math.max(maxCol, col + word.length); } else { maxRow = Math.max(maxRow, row + word.length); } }); return { rows: maxRow + 1, cols: maxCol + 1 }; }; // 生成初始矩阵并标记特殊格子 const generateBoardMatrix = (data) => { const { rows, cols } = calculateBoardSize(data); // 默认全白格 const matrix = Array(rows).fill().map(() => Array(cols).fill(1)); // 标记横向单词起始格 data.across.forEach(word => { const [row, col] = word.position; matrix[row][col] = 2; }); // 标记纵向单词起始格 data.down.forEach(word => { const [row, col] = word.position; matrix[row][col] = 2; }); // 手动标记黑格(示例:第2行第3列设为黑格) // if (matrix[2]?.[3] !== undefined) matrix[2][3] = 0; return matrix; };
2. 渲染棋盘组件
用ScrollView包裹所有行,每行是一个横向View,内部渲染单个格子组件:
import React from 'react'; import { View, ScrollView, Text, StyleSheet } from 'react-native'; // 单个格子组件 const CrosswordCell = ({ type, number }) => { return ( <View style={[ styles.cell, type === 0 ? styles.blackCell : styles.whiteCell, type === 2 && styles.startCell ]}> {/* 显示起始格数字 */} {type === 2 && <Text style={styles.cellNumber}>{number}</Text>} {/* 这里可以添加输入框或答案文本 */} </View> ); }; // 棋盘主组件 const CrosswordBoard = ({ data }) => { const matrix = generateBoardMatrix(data); // 映射起始格对应的数字 const startNumberMap = {}; data.across.forEach(word => { const key = `${word.position[0]}-${word.position[1]}`; startNumberMap[key] = word.id; }); data.down.forEach(word => { const key = `${word.position[0]}-${word.position[1]}`; // 同一格子如果是横竖起始,保留先出现的数字 startNumberMap[key] = startNumberMap[key] || word.id; }); return ( <ScrollView contentContainerStyle={styles.boardWrapper}> {matrix.map((row, rowIdx) => ( <View key={rowIdx} style={styles.row}> {row.map((cellType, colIdx) => ( <CrosswordCell key={`${rowIdx}-${colIdx}`} type={cellType} number={startNumberMap[`${rowIdx}-${colIdx}`]} /> ))} </View> ))} </ScrollView> ); }; // 样式定义 const styles = StyleSheet.create({ boardWrapper: { padding: 12, alignItems: 'center', }, row: { flexDirection: 'row', }, cell: { width: 42, height: 42, borderWidth: 1, borderColor: '#222', justifyContent: 'flex-start', alignItems: 'flex-start', padding: 3, }, blackCell: { backgroundColor: '#222', }, whiteCell: { backgroundColor: '#fff', }, startCell: { backgroundColor: '#f5f5f5', }, cellNumber: { fontSize: 11, color: '#222', }, }); export default CrosswordBoard;
额外实用建议
- 把格子的输入逻辑拆成独立组件(比如
CellInput),负责处理用户输入、答案校验,避免棋盘组件逻辑臃肿。 - 如果棋盘尺寸过大,可考虑用
VirtualizedList实现行级虚拟化,但普通填字游戏用嵌套View性能足够。 - 黑格信息可以单独维护一个坐标数组(比如
blackCells: [[2,3], [4,1]]),生成矩阵时批量标记,更易维护。
内容的提问来源于stack exchange,提问作者A Drunken Turtle
相关产品推荐
相关产品推荐

