集成ExpansionTileController后Flutter应用点击ExpansionTile崩溃求助
解决ExpansionTileController引发的点击崩溃问题
错误原因
断言'widget.controller?._state == null'失败的核心原因是:同一个ExpansionTileController被重复绑定到多个ExpansionTile的State实例。你给ListView设置了UniqueKey(),每次调用setState时,整个ListView会被完全重建,旧的ExpansionTile实例被销毁,但控制器仍持有旧的State引用,新创建的ExpansionTile尝试复用同一个控制器时,就触发了这个断言。
解决方案
步骤1:移除ListView的UniqueKey
去掉ListView.builder的key: UniqueKey(),让ListView根据item的key自动复用或重建子项,避免全局重建导致控制器绑定冲突。
步骤2:优化控制器逻辑(可选)
如果需要保持“同时只能展开一个Tile”的逻辑,当前的selectedTile逻辑可以保留,无需额外修改控制器的初始化方式。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class MyWidget extends StatefulWidget { const MyWidget({super.key}); @override State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { int selectedTile = -1; final tileControllers = List.generate(5, (_) => ExpansionTileController()); @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( itemCount: 5, itemBuilder: (context, index) { return ExpansionTile( key: Key(index.toString()), controller: tileControllers[index], initiallyExpanded: index == selectedTile, title: Text('ExpansionTile $index'), subtitle: const Text('Trailing expansion arrow icon'), onExpansionChanged: ((newState) { setState(() { selectedTile = newState ? index : -1; }); }), children: [ ListTile( title: Text('This is tile number $index'), ), ], ); }, ), ); } }
补充说明
如果确实需要重建整个ListView(比如数据源发生根本性变化),可以在重建前重置所有控制器,确保控制器不再持有旧的State引用:
setState(() { tileControllers.forEach((controller) => controller.reset()); // 其他状态更新逻辑 });
内容的提问来源于stack exchange,提问作者Michael Roebbeling
相关产品推荐
相关产品推荐

