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

Flutter中逻辑应该放在哪里?数独开发顶层逻辑如何获取Square状态

Flutter数独全局状态管理解决方案

核心改造方向(推荐):状态上移到全局逻辑层统一管理

你当前已经在使用LogicalBoard作为全局通知层,只需要把分散在各个Square组件内部的状态全部上移到LogicalBoard中存储即可,完全不需要更换整体架构,改造成本极低:

  • 在LogicalBoard中新增长度为81的状态列表,比如List<SquareData> squareStateList,每个SquareData实例存储对应单元格的所有状态:mainNumber、9个小数字显隐状态、选中状态等
  • 将Square组件改为无状态组件,所有渲染需要的状态都从LogicalBoard.squareStateList[widget.squareIndex]中读取
  • 所有用户交互触发的状态修改,都直接调用LogicalBoard的方法修改对应下标的SquareData,再触发全局通知更新即可
  • 顶层游戏逻辑需要查询任意单元格状态时,直接读取LogicalBoard.squareStateList对应下标的数据即可,后续做全局校验、悔棋、答案提示等功能都非常方便

临时方案(不推荐长期使用):用GlobalKey获取组件State

如果你不想改动现有Square自己存状态的逻辑,也可以通过Flutter的GlobalKey直接获取每个Square的State实例读取状态:

  • 顶层创建长度为81的GlobalKey列表:List<GlobalKey<_SquareState>> squareKeys = List.generate(81, (index) => GlobalKey());
  • 初始化每个Square时,将对应下标的key传给Square的key参数
  • 需要读取状态时,直接通过squareKeys[index].currentState即可拿到对应单元格的内部状态,注意如果要读取私有属性,需要给_SquareState类的属性新增公开getter,或者把属性的下划线去掉改为公开

现有代码优化提示

你当前把监听器注册逻辑写在了build方法中,每次组件重绘都会重复添加监听器,会触发内存泄漏和逻辑重复执行的问题,需要把监听器注册逻辑移到initState中,dispose时移除:

class _SquareState extends State<Square> {
  int _mainNumber = 0;
  bool showEdit1 = false;
  bool showEdit2 = false;
  bool showEdit3 = false;
  bool showEdit4 = false;
  bool showEdit5 = false;
  bool showEdit6 = false;
  bool showEdit7 = false;
  bool showEdit8 = false;
  bool showEdit9 = false;
  bool _selected = false;
  bool _selectedCollection = false;

  @override
  void initState() {
    super.initState();
    LogicalBoard.numberButtonNotifier.addListener(_onNumberUpdate);
    LogicalBoard.selectionNotifier.addListener(_onSelectionUpdate);
  }

  @override
  void dispose() {
    LogicalBoard.numberButtonNotifier.removeListener(_onNumberUpdate);
    LogicalBoard.selectionNotifier.removeListener(_onSelectionUpdate);
    super.dispose();
  }

  void _onNumberUpdate() {
    if(LogicalBoard.selectedSquare?.squareIndex == widget.squareIndex){
      setState(() {
        _mainNumber = LogicalBoard.numberLastClicked;
      });
    }
  }

  void _onSelectionUpdate() {
    setState(() {
      _selected = LogicalBoard.selectedSquare?.squareIndex == widget.squareIndex;
      _selectedCollection =
          LogicalBoard.selectedSquare?.squareIndex == widget.squareIndex ||
              LogicalBoard.selectedSquare?.rowIndex == widget.rowIndex ||
              LogicalBoard.selectedSquare?.colIndex == widget.colIndex ||
              LogicalBoard.selectedSquare?.boxIndex == widget.boxIndex;
    });
  }

  @override
  Widget build(BuildContext context) {
    // 原build逻辑移除addListener部分,其余保持不变
    return Material(
        child: InkWell(
            onTap: () => LogicalBoard.selectionNotifier
                .setSelectedSquare(widget.squareIndex),
            child: Container(
              padding: const EdgeInsets.all(2.0),
              color: _selected
                  ? Theme.of(context).errorColor
                  : Theme.of(context).primaryColorDark,
              width: 52.0,
              height: 52.0,
              child: Container(
                  padding: _mainNumber == 0
                      ? const EdgeInsets.fromLTRB(2.0, 8.0, 2.0, 2.0)
                      : const EdgeInsets.all(0.0),
                  color: _selectedCollection
                      ? Theme.of(context).backgroundColor
                      : Theme.of(context).primaryColor,
                  width: 48.0,
                  height: 48.0,
                  child: _mainNumber != 0
                      ? Center(
                          child: Text(
                          _mainNumber.toString(),
                          style: Theme.of(context).textTheme.headline3,
                        ))
                      : Column(mainAxisSize: MainAxisSize.min, children: [
                          Flexible(
                              child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                Flexible(
                                    child: Text(
                                  showEdit1 ? "1" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit2 ? "2" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit3 ? "3" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                ))
                              ])),
                          Flexible(
                              child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                Flexible(
                                    child: Text(
                                  showEdit4 ? "4" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit5 ? "5" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit6 ? "6" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                ))
                              ])),
                          Flexible(
                              child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                Flexible(
                                    child: Text(
                                  showEdit7 ? "7" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit8 ? "8" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                )),
                                Flexible(
                                    child: Text(
                                  showEdit9 ? "9" : "",
                                  style: Theme.of(context).textTheme.bodyText2,
                                ))
                              ]))
                        ])),
            )));
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:54:03