Flutter Animated List报错:RangeError (index): 无效值:有效范围为空:0
解决Flutter AnimatedList的RangeError索引越界问题
错误根源
- 你给
AnimatedList设置了initialItemCount: serverList.length,但animatedTiles初始为空,且是通过Future.delayed延迟逐个添加元素的。AnimatedList会立即根据initialItemCount尝试渲染所有item,此时animatedTiles的长度远小于serverList.length,调用animatedTiles[index]就会触发索引越界错误。 - 额外问题:
dispose方法里的_controller未定义,会导致另一个运行时错误。
修复方案
方案1:动态从零构建AnimatedList(推荐,保留逐个添加的动画效果)
去掉initialItemCount(默认值为0),完全通过insertItem动态添加元素,确保animatedTiles的长度和AnimatedList的item数量同步。
修改后的核心代码:
class _ServerListViewState extends State<ServerListView> { final List<ServerList> serverList = List.from(servers); List<Widget> animatedTiles = []; final GlobalKey<AnimatedListState> _listkey = GlobalKey<AnimatedListState>(); final Tween<Offset> _offset = Tween(begin: const Offset(1, 0), end: const Offset(0, 0)); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { addServer(); }); } void addServer() { Future loading = Future(() {}); for (var server in serverList) { loading = loading.then((_) { return Future.delayed(const Duration(milliseconds: 100), () { final index = animatedTiles.length; animatedTiles.add( ServerCard(serverItem: server, onTap: () {}), ); _listkey.currentState!.insertItem(index); }); }); } } @override void dispose() { super.dispose(); // 删除未定义的_controller.dispose()调用 } @override Widget build(BuildContext context) { return ViewModelBuilder<ServerListViewModel>.reactive( builder: (context, model, child) => Scaffold( // 其他代码保持不变 body: serverList.isEmpty ? const _EmptyServer() : Column( children: <Widget>[ verticalSpaceMini, Expanded( child: AnimatedList( shrinkWrap: true, padding: kEdgeInsetsAllMedium, key: _listkey, // 移除initialItemCount配置,默认从0开始 itemBuilder: (context, index, animation) { return SlideTransition( position: animation.drive(_offset), child: Slidable( endActionPane: ActionPane( motion: const StretchMotion(), children: [ SlidableAction( onPressed: ((context) {}), icon: Icons.delete, backgroundColor: AppColor.kErrorColor, label: "Delete", ), ]), child: animatedTiles[index]), ); }, ), ), ], ), // 其他代码保持不变 ), viewModelBuilder: () => ServerListViewModel(), ); } }
方案2:初始化时填充animatedTiles(适用于不需要逐个添加动画的场景)
如果不需要延迟逐个添加的动画效果,可以在initState里直接填充animatedTiles,确保initialItemCount和animatedTiles长度一致:
@override void initState() { super.initState(); // 直接初始化所有卡片,无需延迟添加 animatedTiles = serverList.map((server) => ServerCard(serverItem: server, onTap: () {})).toList(); } // 删除addServer方法,因为不需要动态添加逻辑
此时AnimatedList的initialItemCount: serverList.length可以保留,itemBuilder中调用animatedTiles[index]不会出现索引越界。
额外注意点
- 后续实现删除功能时,需同步从
animatedTiles移除对应元素,并调用_listkey.currentState!.removeItem()方法,保持数据与UI状态一致。 - 搜索功能中的
ServerCard参数缺失,需补全对应属性避免UI渲染异常。
内容的提问来源于stack exchange,提问作者Joel Stephen
相关产品推荐
相关产品推荐

