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

如何实现带全选/取消全选功能的三态CheckBox树形视图(TreeView)

实现n级带CheckBox的树形视图思路

1. 定义递归数据模型

先构建支持嵌套的节点模型,包含状态控制字段:

class TreeNode {
  final String id;
  final String name;
  bool isChecked;
  bool isIndeterminate; // 半选状态标记
  bool isExpanded;
  List<TreeNode> children;

  TreeNode({
    required this.id,
    required this.name,
    this.isChecked = false,
    this.isIndeterminate = false,
    this.isExpanded = false,
    this.children = const [],
  });
}

2. 实现CheckBox联动逻辑

核心处理选中状态的递归联动:

  • 父节点选中/取消:递归同步所有子节点的选中状态,清除半选标记
  • 子节点状态变化:向上遍历更新父节点状态:
    • 所有子节点全选中 → 父节点设为选中,清除半选
    • 所有子节点全未选中 → 父节点设为未选中,清除半选
    • 部分子节点选中 → 父节点设为半选

示例逻辑方法:

// 递归更新子节点状态
void syncChildStatus(TreeNode node, bool isChecked) {
  node.isChecked = isChecked;
  node.isIndeterminate = false;
  for (var child in node.children) {
    syncChildStatus(child, isChecked);
  }
}

// 向上更新父节点状态
void updateParentStatus(TreeNode node, List<TreeNode> allNodes) {
  TreeNode? parent = findParentNode(node.id, allNodes); // 需要实现根据id查找父节点的逻辑
  if (parent == null) return;

  bool allChildChecked = parent.children.every((child) => child.isChecked && !child.isIndeterminate);
  bool allChildUnchecked = parent.children.every((child) => !child.isChecked && !child.isIndeterminate);

  if (allChildChecked) {
    parent.isChecked = true;
    parent.isIndeterminate = false;
  } else if (allChildUnchecked) {
    parent.isChecked = false;
    parent.isIndeterminate = false;
  } else {
    parent.isIndeterminate = true;
    parent.isChecked = false;
  }

  // 继续更新上层父节点
  updateParentStatus(parent, allNodes);
}

3. 构建递归渲染Widget

通过递归生成节点视图,根据层级设置缩进,处理展开/折叠:

Widget buildTreeNode(TreeNode node, int level, Function() onRefresh) {
  return Column(
    children: [
      Padding(
        padding: EdgeInsets.only(left: level * 24.0), // 按层级设置缩进
        child: Row(
          children: [
            Checkbox(
              tristate: true,
              value: node.isIndeterminate ? null : node.isChecked,
              onChanged: (bool? value) {
                if (value != null) {
                  syncChildStatus(node, value);
                  updateParentStatus(node, allTreeNodes); // allTreeNodes为全量节点列表
                  onRefresh();
                }
              },
            ),
            Expanded(child: Text(node.name)),
            if (node.children.isNotEmpty)
              IconButton(
                icon: Icon(node.isExpanded ? Icons.expand_less : Icons.expand_more),
                onPressed: () {
                  node.isExpanded = !node.isExpanded;
                  onRefresh();
                },
              ),
          ],
        ),
      ),
      // 展开时渲染子节点
      if (node.isExpanded)
        ...node.children.map((child) => buildTreeNode(child, level + 1, onRefresh)).toList(),
    ],
  );
}

4. 状态管理

用StatefulWidget直接管理全量节点状态,节点状态变化时调用setState触发视图刷新;也可以用Riverpod、Provider等状态库统一管理,适合复杂场景。

关键细节

  • 开启Checkbox的tristate=true属性,实现半选状态展示
  • 通过层级计算缩进,保证树形结构的视觉层级
  • 递归逻辑必须覆盖所有层级,避免状态同步遗漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:49:57