Android扫雷游戏调整minesSeekBar后莫名新增一行按钮问题
扫雷游戏UI异常问题描述
这是一款由按钮构成雷区的扫雷游戏,雷区的gridSize设为4,gridHeight设为8。首次初始化可正常显示4×8的按钮区域,但首次游戏结束后,调整minesSeekBar时,gridHeight未发生修改,雷区却新增了一行按钮。
初始效果:首次游戏界面
异常效果:调整后的界面
无法理解为何gridHeight未修改却新增了一行按钮,怀疑问题出在start.setOnClickListener()中,但未找到修复点,理论上每次点击Start都会重置雷区,应该保持一致。认为setupGame()中不存在问题,因为该方法未修改gridSize。
XML布局代码
<Button android:id="@+id/menu1" android:layout_width="55dp" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginStart="340dp" android:layout_marginTop="10dp" android:background="@drawable/baseline_menu_24" app:cornerRadius="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" /> <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="START" android:layout_marginTop="5dp" android:layout_marginStart="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.005" tools:ignore="MissingConstraints" /> <EditText android:layout_marginStart="10dp" android:id="@+id/einsatz" android:layout_marginTop="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Einsatz" android:inputType="number" android:textColor="@color/black" android:textColorHighlight="@color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <SeekBar android:id="@+id/sizeSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="8" android:progress="2" app:layout_constraintBottom_toTopOf="@+id/gridlayout" app:layout_constraintTop_toTopOf="parent" tools:layout_editor_absoluteX="10dp" android:visibility="gone"/> <SeekBar android:id="@+id/minesSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="16" android:progress="2" app:layout_constraintBottom_toTopOf="@+id/gridlayout" app:layout_constraintTop_toBottomOf="@+id/start" tools:layout_editor_absoluteX="10dp" /> <GridLayout android:id="@+id/gridlayout" android:layout_width="match_parent" android:layout_height="400dp" android:layout_marginBottom="52dp" android:layout_weight="1" android:background="@drawable/custom_edittext" android:columnCount="4" android:rowCount="4" app:layout_constraintBottom_toBottomOf="parent" tools:layout_editor_absoluteX="9dp" />
Java主类代码
public class Minen extends AppCompatActivity { private int gridSize = 4; // 默认网格行数 private int gridHeight = 8; // 默认网格列数 private int numMines = 2; // 默认地雷数量 private ArrayList<ArrayList<Button>> buttons; private ArrayList<ArrayList<Boolean>> minePositions; private boolean gameLost = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_minefield); getSupportActionBar().hide(); Button menu = findViewById(R.id.menu1); GridLayout gridLayout = findViewById(R.id.gridlayout); SeekBar heightSeekBar = findViewById(R.id.sizeSeekBar); SeekBar minesSeekBar = findViewById(R.id.minesSeekBar); Button start = findViewById(R.id.start); // 设置高度滑块监听 heightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { int x = progress + 1; // 调整范围为2到10 setupGame(); } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); minesSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { numMines = progress; setupGame(); } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }); // 初始化按钮和地雷位置集合 buttons = new ArrayList<>(); minePositions = new ArrayList<>(); start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (getEinsatzFromEditText() > 0) { kontostandpositiv(getEinsatzFromEditText(), new Callback() { @Override public void Callbackchecked(boolean kontostandPositiv) { if (kontostandPositiv) { kontostandandernminus(getEinsatzFromEditText()); for (int i = 0; i < gridSize; i++) { ArrayList<Button> rowButtons = new ArrayList<>(); ArrayList<Boolean> rowMinePositions = new ArrayList<>(); for (int j = 0; j < gridHeight; j++) { Button button = new Button(getApplicationContext()); int finalI = i; int finalJ = j; button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!gameLost) { if (minePositions.get(finalI).get(finalJ)) { gameLost = true; showGameOver(); } else { button.setEnabled(false); calcwin(); checkForWin(); } } } }); rowButtons.add(button); rowMinePositions.add(false); gridLayout.addView(button); } buttons.add(rowButtons); minePositions.add(rowMinePositions); } setupGame(); } else { Toast.makeText(Minen.this, "余额不足", Toast.LENGTH_SHORT).show(); } } }); } else { Toast.makeText(Minen.this, "请设置赌注", Toast.LENGTH_SHORT).show(); } } });
相关方法代码
setupGame()
private void setupGame() { gameLost = false; // 重置按钮状态和地雷位置 for (int i = 0; i < gridSize; i++) { for (int j = 0; j < gridHeight; j++) { Button button = buttons.get(i).get(j); button.setEnabled(true); button.setText(""); minePositions.get(i).set(j, false); } } // 随机生成地雷位置 generateMinePositions(); }
generateMinePositions()
private void generateMinePositions() { Random random = new Random(); int minesPlaced = 0; while (minesPlaced < numMines) { int row = random.nextInt(4); int col = random.nextInt(gridHeight); if (!minePositions.get(row).get(col)) { minePositions.get(row).set(col, true); minesPlaced++; } } }
showGameOver()
private void showGameOver() { Toast.makeText(this, "游戏结束!你踩到了地雷。", Toast.LENGTH_SHORT).show(); for (int i = 0; i < gridSize; i++) { for (int j = 0; j < gridHeight; j++) { if (minePositions.get(i).get(j)) { buttons.get(i).get(j).setText("X"); } buttons.get(i).get(j).setEnabled(false); } } }
checkForWin()
private void checkForWin() { for (int i = 0; i < gridSize; i++) { for (int j = 0; j < gridHeight; j++) { if (!minePositions.get(i).get(j) && buttons.get(i).get(j).isEnabled()) { return; // 还有未翻开的非地雷格子 } } } Toast.makeText(this, "恭喜!你获胜了!", Toast.LENGTH_SHORT).show(); }
问题原因与修复方案
核心问题
每次点击Start按钮时,你都在重复向GridLayout中添加新按钮,但没有先清空之前的按钮和数据集合。调整minesSeekBar触发setupGame()时,虽然重置了现有按钮状态,但之前多次点击Start积累的按钮还留在GridLayout里,导致显示行数异常。
另外还有两个次要问题:
heightSeekBar的监听逻辑错误,没有将进度值赋值给gridHeight,导致滑动该SeekBar不会改变雷区高度。generateMinePositions()中固定用random.nextInt(4)生成行索引,应该改用gridSize变量,适配动态行数。
修复步骤
点击Start前清空GridLayout与数据集合
在Start按钮的点击事件中,先清空buttons、minePositions集合,同时移除GridLayout中的所有子View:start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (getEinsatzFromEditText() > 0) { kontostandpositiv(getEinsatzFromEditText(), new Callback() { @Override public void Callbackchecked(boolean kontostandPositiv) { if (kontostandPositiv) { kontostandandernminus(getEinsatzFromEditText()); // 新增:清空旧数据和视图 buttons.clear(); minePositions.clear(); gridLayout.removeAllViews(); for (int i = 0; i < gridSize; i++) { // 原有生成按钮的代码... } setupGame(); } else { Toast.makeText(Minen.this, "余额不足", Toast.LENGTH_SHORT).show(); } } }); } else { Toast.makeText(Minen.this, "请设置赌注", Toast.LENGTH_SHORT).show(); } } });修复heightSeekBar的赋值逻辑
修改heightSeekBar的监听,将进度值正确赋值给gridHeight:heightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { gridHeight = progress + 1; // 调整范围为2到10 setupGame(); } // 其他方法不变... });修复generateMinePositions()的行索引生成
把固定的4改为gridSize:private void generateMinePositions() { Random random = new Random(); int minesPlaced = 0; while (minesPlaced < numMines) { int row = random.nextInt(gridSize); // 改用gridSize变量 int col = random.nextInt(gridHeight); if (!minePositions.get(row).get(col)) { minePositions.get(row).set(col, true); minesPlaced++; } } }
内容的提问来源于stack exchange,提问作者Jonasoos
相关产品推荐
相关产品推荐

