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

Flutter贪吃蛇游戏:build方法使用旧grid变量致界面无变化

问题解决:Flutter贪吃蛇界面不更新

核心问题分析

  1. setState滥用且位置错误:gameTick中循环修改蛇身坐标时,每次循环都调用setState,不仅触发多次不必要的UI重建,还可能导致状态更新不连贯。
  2. grid变量引用未更新:grid作为类成员变量,直接修改列表内的Container元素时,列表本身的引用没有变化,Flutter状态检测机制会认为数据未改变,因此不更新UI。
  3. Timer未正确赋值:initState中创建的Timer没有赋值给类成员timer,导致dispose时无法正确取消定时器。

修复后的代码

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:swipe/swipe.dart';

void main() {
  runApp(
    MaterialApp(
      title: 'snake',
      theme: ThemeData(
        brightness: Brightness.dark,
        primaryColor: Colors.blueGrey,
      ),
      home: Game(),
    ),
  );
}

class Game extends StatefulWidget {
  const Game({Key? key}) : super(key: key);

  @override
  State<Game> createState() => _GameState();
}

class _GameState extends State<Game> {
  List<List<int>> snake = [
    [5, 5],
    [6, 5],
    [7, 5]
  ];
  Timer? timer;

  @override
  void initState() {
    // 正确赋值timer,确保dispose时能取消
    timer = Timer.periodic(Duration(seconds: 1), (Timer t) => gameTick());
    super.initState();
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  void gameTick() {
    // 把所有蛇身修改逻辑包裹在一次setState中
    setState(() {
      for (List<int> pair in snake) {
        pair[0]--;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    // 每次build时重新创建grid列表,确保引用更新
    List<Container> grid = [];
    for (int i = 0; i < 121; i++) {
      int row = (i / 11).floor();
      int col = i % 11;
      bool isSnake = false;

      // 先判断当前格子是否属于蛇身
      for (List<int> pair in snake) {
        if (pair[0] == row && pair[1] == col) {
          isSnake = true;
          break;
        }
      }

      grid.add(Container(
        decoration: BoxDecoration(
          color: isSnake ? Colors.greenAccent : null,
          border: Border.all(
            color: isSnake ? Color(0xFF383434) : Colors.greenAccent,
            width: 2,
          ),
        ),
      ));
    }

    return Scaffold(
      body: SizedBox.expand(
        child: Swipe(
          onSwipeUp: () { /* 你的滑动逻辑 */ },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Expanded(
                child: GridView.count(
                  physics: NeverScrollableScrollPhysics(),
                  crossAxisCount: 11,
                  children: grid,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

关键修改点说明

  • 优化setState调用:将蛇身的所有坐标修改放在一次setState中,确保状态更新后只触发一次UI重建,避免多次重建导致的性能问题和状态不一致。
  • 重建grid列表:在build方法中每次创建新的grid列表,而非修改类成员变量的元素。这样每次状态变化时,GridView会接收到新的列表引用,从而触发UI更新。
  • 修复Timer赋值:initState中创建Timer时赋值给timer变量,保证dispose时能正确取消定时器,避免内存泄漏。
  • 简化格子判断逻辑:先判断当前格子是否属于蛇身,再统一创建Container,让代码更清晰易读。

内容的提问来源于stack exchange,提问作者DR4NKR1D3R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:35:35