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

使用ListView.builder实现单ExpansionTile展开时遇_state != null断言错误

解决ListView.builder中单一展开ExpansionTile的断言错误问题

问题根源

你遇到的Error: Assertion failed: _state != null错误,是因为expansionControllers在build方法内生成,每次setState都会重建控制器实例,导致新控制器与ExpansionTile的内部状态解绑,出现_state为空的情况。同时当前代码未处理收起之前展开tile的逻辑,无法实现单一展开的需求。

修复方案

  1. 将控制器和跟踪变量提升为State类成员
    把expansionControllers和prevIndexExpanded移到State类的成员变量中,在initState里初始化控制器,确保实例稳定,不会随build重建。

  2. 在展开时自动收起之前的tile
    在onExpansionChanged回调中,先判断是否有已展开的tile,调用对应控制器的collapse()方法收起,再更新当前展开的索引。

完整代码示例

class SingleExpansionList extends StatefulWidget {
  final List<YourDataModel> data; // 替换成你的数据模型类
  const SingleExpansionList({super.key, required this.data});

  @override
  State<SingleExpansionList> createState() => _SingleExpansionListState();
}

class _SingleExpansionListState extends State<SingleExpansionList> {
  late List<ExpansionTileController> expansionControllers;
  int? prevIndexExpanded;

  @override
  void initState() {
    super.initState();
    // 在initState中初始化控制器,保证实例唯一
    expansionControllers = List.generate(
      widget.data.length,
      (index) => ExpansionTileController(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: widget.data.length,
      itemBuilder: (context, index) {
        return ExpansionTile(
          controller: expansionControllers[index],
          leading: Text(widget.data[index].code),
          title: Text(widget.data[index].name),
          onExpansionChanged: (value) async {
            if (value) {
              // 收起之前展开的tile(如果存在且不是当前索引)
              if (prevIndexExpanded != null && prevIndexExpanded != index) {
                await expansionControllers[prevIndexExpanded!].collapse();
              }
              setState(() {
                prevIndexExpanded = index;
              });
              // 这里执行你的其他业务逻辑
            } else {
              // 收起当前tile时,重置跟踪索引
              setState(() {
                prevIndexExpanded = null;
              });
            }
          },
          children: [
            // 你的子组件内容示例
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text(widget.data[index].detail),
            ),
          ],
        );
      },
    );
  }
}

关键说明

  • 控制器必须在initState初始化,避免每次build重建导致的状态不匹配问题。
  • 使用await等待collapse()完成,确保状态更新后再设置新的展开索引,避免UI异常。
  • 处理收起当前tile的情况,重置prevIndexExpanded,保证逻辑完整性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:32:28