Android单词搜索游戏RecyclerView随意拖拽问题求助
解决Android单词搜索游戏无规则拖拽选择问题
问题分析
你的代码在处理触摸拖拽时,未对选中单元格做合法性校验——ACTION_MOVE触发时直接将当前触摸单元格加入选中集合,导致用户可以无规则选择任意路径的单元格,不符合单词搜索游戏只能沿直线(水平、垂直、对角线)连续选择的规则。此外,processSelectedCells中通过字符串排序拼接单词的逻辑存在错误,会打乱实际选中顺序,导致单词拼接结果不符合用户操作路径。
解决方案
需要添加以下核心校验逻辑:
- 记录初始选中单元格、上一个选中单元格的位置,以及当前选择的方向
- 在
ACTION_MOVE时校验当前单元格:- 与上一个选中单元格相邻(8个方向范围内)
- 若已有选择方向,后续单元格必须保持同一方向(避免中途变向)
- 未被重复选中
- 改用有序集合记录选中单元格,保证单词拼接顺序与用户操作一致
修改后的代码
1. 添加成员变量
在Activity类中添加以下成员变量,用于跟踪选择状态:
private int startRow = -1; private int startCol = -1; private int lastRow = -1; private int lastCol = -1; // 方向标记:0=未确定,1=右,2=左,3=下,4=上,5=右下,6=左下,7=右上,8=左上 private int currentDirection = 0; // 用LinkedHashMap保证插入顺序,替代原HashMap private LinkedHashMap<String, Cell> currentSelectedCells = new LinkedHashMap<>();
2. 替换RecyclerView触摸监听逻辑
替换原来的recyclerView.addOnItemTouchListener代码块:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent event) { int action = event.getActionMasked(); int position = getPosUnderTouch(event); if (position != RecyclerView.NO_POSITION) { int row = position / cells.get(0).size(); int col = position % cells.get(0).size(); Cell cell = cells.get(row).get(col); switch (action) { case MotionEvent.ACTION_DOWN: // 重置选择状态 startRow = row; startCol = col; lastRow = row; lastCol = col; currentDirection = 0; currentSelectedCells.clear(); // 选中初始单元格 cell.setSelected(true); currentSelectedCells.put(row + "-" + col, cell); adapter.notifyItemChanged(position); break; case MotionEvent.ACTION_MOVE: // 校验当前单元格是否符合规则,符合才选中 if (isValidCell(row, col)) { cell.setSelected(true); currentSelectedCells.put(row + "-" + col, cell); adapter.notifyItemChanged(position); // 更新上一个位置和方向 lastRow = row; lastCol = col; if (currentDirection == 0) { currentDirection = calculateDirection(startRow, startCol, row, col); } } break; case MotionEvent.ACTION_UP: processSelectedCells(currentSelectedCells); // 重置状态 startRow = -1; startCol = -1; lastRow = -1; lastCol = -1; currentDirection = 0; currentSelectedCells.clear(); break; case MotionEvent.ACTION_CANCEL: // 取消选择,重置未找到的单元格选中状态 for (Cell c : currentSelectedCells.values()) { if (!c.isFound()) { c.setSelected(false); } } adapter.notifyDataSetChanged(); // 重置状态 startRow = -1; startCol = -1; lastRow = -1; lastCol = -1; currentDirection = 0; currentSelectedCells.clear(); break; default: break; } } return false; } @Override public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent event) {} @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} });
3. 添加校验与方向计算辅助方法
在Activity类中添加以下工具方法:
// 校验当前单元格是否符合选择规则 private boolean isValidCell(int currentRow, int currentCol) { // 不能重复选中同一单元格 if (currentSelectedCells.containsKey(currentRow + "-" + currentCol)) { return false; } // 必须与上一个单元格相邻(8个方向内) int rowDiff = Math.abs(currentRow - lastRow); int colDiff = Math.abs(currentCol - lastCol); if (rowDiff > 1 || colDiff > 1) { return false; } // 已有方向时,必须保持同一方向 if (currentDirection != 0) { int expectedDirection = calculateDirection(lastRow, lastCol, currentRow, currentCol); return expectedDirection == currentDirection; } return true; } // 计算两个单元格之间的方向 private int calculateDirection(int fromRow, int fromCol, int toRow, int toCol) { int rowDiff = toRow - fromRow; int colDiff = toCol - fromCol; if (rowDiff == 0) { return colDiff > 0 ? 1 : 2; // 右=1,左=2 } else if (colDiff == 0) { return rowDiff > 0 ? 3 : 4; // 下=3,上=4 } else if (rowDiff > 0 && colDiff > 0) { return 5; // 右下 } else if (rowDiff > 0 && colDiff < 0) { return 6; // 左下 } else if (rowDiff < 0 && colDiff > 0) { return 7; // 右上 } else { return 8; // 左上 } }
4. 修改processSelectedCells方法
替换原方法,使用LinkedHashMap的插入顺序拼接单词:
private void processSelectedCells(LinkedHashMap<String, Cell> selectedCells) { // 按用户选中顺序拼接单词 StringBuilder selectedWordBuilder = new StringBuilder(); for (Cell cell : selectedCells.values()) { selectedWordBuilder.append(cell.getLetter()); } String selectedWord = selectedWordBuilder.toString(); txtSelected.setText(selectedWord); // 检查是否匹配目标单词(支持正向/反向匹配,可按需关闭反向) boolean wordFound = false; for (Word word : wordsOnBoard) { String targetWord = word.getWordText(); if (selectedWord.equals(targetWord) || selectedWord.equals(new StringBuilder(targetWord).reverse().toString())) { Toast.makeText(getApplicationContext(), "找到单词: " + targetWord, Toast.LENGTH_SHORT).show(); word.setFound(true); for (Cell cell : word.getCells()) { cell.setFound(true); cell.setSelected(false); // 切换为已找到状态 } wordFound = true; break; } } // 未找到单词,重置选中状态 if (!wordFound) { for (Cell cell : selectedCells.values()) { if (!cell.isFound()) { cell.setSelected(false); } } Toast.makeText(this, selectedWord + " 不在单词列表中", Toast.LENGTH_SHORT).show(); } adapter.notifyDataSetChanged(); }
说明
- 上述代码限制了只能沿单一方向连续选择相邻单元格,符合单词搜索游戏的常规规则
- 支持正向和反向匹配单词,可根据需求删除反向匹配逻辑
- 使用LinkedHashMap保证单词拼接顺序与用户操作路径一致,避免了原代码排序导致的错误
内容的提问来源于stack exchange,提问作者Faiz Agil Wirawan
相关产品推荐
相关产品推荐

