You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android单词搜索游戏RecyclerView随意拖拽问题求助

解决Android单词搜索游戏无规则拖拽选择问题

问题分析

你的代码在处理触摸拖拽时,未对选中单元格做合法性校验——ACTION_MOVE触发时直接将当前触摸单元格加入选中集合,导致用户可以无规则选择任意路径的单元格,不符合单词搜索游戏只能沿直线(水平、垂直、对角线)连续选择的规则。此外,processSelectedCells中通过字符串排序拼接单词的逻辑存在错误,会打乱实际选中顺序,导致单词拼接结果不符合用户操作路径。

解决方案

需要添加以下核心校验逻辑:

  • 记录初始选中单元格、上一个选中单元格的位置,以及当前选择的方向
  • 在ACTION_MOVE时校验当前单元格:
    1. 与上一个选中单元格相邻(8个方向范围内)
    2. 若已有选择方向,后续单元格必须保持同一方向(避免中途变向)
    3. 未被重复选中
  • 改用有序集合记录选中单元格,保证单词拼接顺序与用户操作一致

修改后的代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:24:54