SetState не работает для одной из переменных (переменная имеет значение null при перестройке) - PullRequest
0 голосов
/ 13 марта 2020

У меня есть приложение тральщика, которое содержит одну панель приложений (с кнопкой перезапуска смайлика), один bottomAppBar (с кнопками уровня) и одну доску (которая, в свою очередь, имеет поля).

Я использую setState() установить выигрыш и попытаться использовать его для установки уровня игры через _level. Но к тому времени, когда виджет перестраивается (с помощью setState, запускаемого одной из кнопок уровня), переменная _level снова становится равной нулю.

Нужно ли перемещать состояние _level вверх в дерево виджетов? Имеет ли это какое-то отношение к используемому виджету LayoutBuilder?

class MinesweeperApp extends StatefulWidget {
  @override
  _MinesweeperAppState createState() => _MinesweeperAppState();
}

class _MinesweeperAppState extends State<MinesweeperApp> {
  bool _win;
  Board _board;
  Level _level;



  Board _getBoard(
    double width,
    double height,
  ) {
    if (_board == null) {
      int qtyOfColumns = (width / (width * 0.09)).floor();
      double fieldSize = width / qtyOfColumns;
      int qtyOfRows = (height / fieldSize).floor();
      _board = Board(
          qtyOfRows: qtyOfRows, qtyOfColumns: qtyOfColumns, level: _level==null ? Level.medium : _level);
    }
    return _board;
  }


@override
  void initState() {
    _level = Level.medium;
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        bottomNavigationBar: BottomAppBar(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              FlatButton(
                child: Text('EASY'),
                onPressed: () {

                  _onRestart(Level.easy);

                },
              ),
              FlatButton(
                child: Text('MEDIUM'),
                onPressed: () {
                  _onRestart(Level.medium);


                },
              ),
              FlatButton(
                child: Text('HARD'),
                onPressed: () {
                  _onRestart(Level.hard);

                },
              ),
            ],
          ),
        ),
        appBar: MinesweeperAppBar(
          win: _win,
          onRestart: ()=>_onRestart(_level),
        ),
        body: Center(
          child: LayoutBuilder(
            builder: (context, constraints) {
              return BoardWidget(
                board: _getBoard( constraints.maxWidth, constraints.maxHeight),
                onOpen: _open,
                onToggleMarked: _toggleMarked,
              );
            },
          ),
        ),
      ),
    );
  }

  void _open(Field field) {
    setState(() {
      if (_win != null) {
        return;
      }

      try {
        field.open();
        if (_board.solved) {
          _win = true;
        }
      } on ExplosionException {
        _win = false;
        _board.revealMines();
      }
    });
  }

  void _toggleMarked(Field field) {
    if (_win != null) {
      return;
    }
    setState(() {
      field.toggleMarked();
      if (_board.solved) {
        _win = true;
      }
    });
  }

  void _onRestart(Level level) {
    setState(() {
      _level = level;
      _win = null;
      _board.restartGame();
    });
  }
}

Кроме того, кто-нибудь знает источник для изучения такого поведения setState (простого, так как я не разбираюсь в технических деталях) )? Я пытаюсь обдумать эту концепцию.

...