flutter 主应用小部件:setState调用->build()构建所有小部件,但屏幕未更新

kq0g1dla  于 2022-11-30  发布在  Flutter
关注(0)|答案(2)|浏览(195)

应用程序是一个简单的记忆/猜谜游戏,带有一个方格。浮动的动作按钮触发“新游戏”对话框,"是"响应触发setState()在主小部件上.打印()调用显示它正在构建网格中的所有Tile小部件,但当它返回时,旧的网格值仍然显示。2可能做了一些愚蠢的事情,但没有看到它。3基本代码如下。4 TIA如果有人可以看到什么是失踪/无效/损坏/等。
dart是创建无状态HomePage的常用main(),它创建使用此State的有状态小部件:

class MemHomePageState extends State<MemHomePage> {

  GameBoard gameBoard = GameBoard();
  GameController? gameController;
  int gameCount = 0, winCount = 0;

  @override
  void initState() {
    super.initState();
    gameController = GameController(gameBoard, this);
  }

  @override
  Widget build(BuildContext context) {
    if (kDebugMode) {
      print("MemHomepageState::build");
    }
    gameBoard.newGame(); // Resets secrets and grids
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: GridView.count(
          crossAxisCount: Globals.num_columns,
          children: List.generate(Globals.num_columns * Globals.num_rows, (index) {
            int x = index~/Globals.NR, y = index%Globals.NR;
            int secret = gameBoard.secretsGrid![x][y];
            var t = Tile(x, y, Text('$secret'), gameController!);
            gameBoard.tilesGrid![x].add(t);
            if (kDebugMode) {
              print("Row $x is ${gameBoard.secretsGrid![x]} ${gameBoard.tilesGrid![x][y].secret}");
            }
            return t;
          }),
        ),
        // Text("You have played $gameCount games and won $winCount."),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => newGameDialog("Start a new game?"),
        tooltip: 'New game?',
        child: const Icon(Icons.refresh_outlined),
      ),
    );
  }

  /** Called from the FAB and also from GameController "won" logic */
  void newGameDialog(String message) {
    showDialog<void>(
        context: context,
        barrierDismissible: false, // means the user must tap a button to exit the Alert Dialog
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text("New game?"),
            content: Text(message),
            //),
            actions: <Widget>[
              TextButton(
                child: const Text('Yes'),
                onPressed: () {
                  setState(() {
                    gameCount++;
                  });
                  Navigator.of(context).pop();
                },
              ),
              TextButton(
                child: const Text('No'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        }
    );
  }

Tile类是一个StatefulWidget,其状态决定了特定图块应显示的内容:

import 'package:flutter/material.dart';
import 'gamecontroller.dart';
    
enum TileMode {
      SHOWN,
      HIDDEN,
      CLEARED,
    }
    
/// Represents one Tile in the game
class Tile extends StatefulWidget {
  final int x, y;
  final Widget secret;
  final GameController gameController;
  TileState? tileState;

  Tile(this.x, this.y, this.secret, this.gameController, {super.key});

  @override
  State<Tile> createState() => TileState(x, y, secret);
    
  setCleared() {
    tileState!.setCleared();
  }
}
    
    class TileState extends State<Tile> {
      final int x, y;
      final Widget secret;
      TileMode tileMode = TileMode.HIDDEN;
    
      TileState(this.x, this.y, this.secret);
    
      _unHide() {
        setState(() => tileMode = TileMode.SHOWN);
        widget.gameController.clicked(widget);
      }
    
      reHide() {
        print("rehiding");
        setState(() => tileMode = TileMode.HIDDEN);
      }
    
      setCleared() {
        print("Clearing");
        setState(() => tileMode = TileMode.CLEARED);
      }
    
      _doNothing() {
        //
      }
    
      @override
      Widget build(BuildContext context) {
        switch(tileMode) {
          case TileMode.HIDDEN:
            return ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.teal,
                ),
                onPressed: _unHide,
                child: Text(''));
          case TileMode.SHOWN:
            return ElevatedButton(
                onPressed: _doNothing,
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.green,
                ),
                child: secret);
          case TileMode.CLEARED:
            return ElevatedButton(
                onPressed: _doNothing,
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.black12,
                ),
                child: const Icon(Icons.check));
        }
      }
    }
k3bvogb1

k3bvogb11#

看起来你在编译函数中调用了下面的函数。2这会导致每次编译时所有的东西都被重置。3也许它属于init?

gameBoard.newGame(); // Resets secrets and grids
x7rlezfr

x7rlezfr2#

最初的问题是Tile对象,虽然正确创建并连接到返回的主部件,但没有明确的'key'值,因此它们没有替换原始对象。UniqueKey()'到循环中的每个Tile(),解决了这个问题。它暴露了一个相关的问题,但超出了这个问题的范围。请查看OP中的github链接以获取最新版本。

相关问题