Flutter ListView带动画排序实现问询:点击调整优先级后如何添加列表过渡动画
Flutter ListView 排序位置交换动画实现方案
核心解决思路:直接调用setState全量更新列表会跳过元素过渡效果,要实现可感知的位置交换动画,需要通过列表动画控制器精准控制发生位置变化的元素的入场、退场动画。
方案1:使用官方自带AnimatedList实现(无第三方依赖)
实现步骤
- 定义全局Key绑定AnimatedList状态,同步维护业务数据列表
- 触发优先级修改后,先定位对应元素的旧索引
oldIndex和排序后的新索引newIndex - 调用
AnimatedListState.removeItem方法移除旧位置元素,自定义移除动画效果 - 同步更新内存中的数据列表,再调用
AnimatedListState.insertItem方法将元素插入新位置,自定义入场动画效果
示例代码
import 'package:flutter/material.dart'; class SortableAnimatedList extends StatefulWidget { const SortableAnimatedList({super.key}); @override State<SortableAnimatedList> createState() => _SortableAnimatedListState(); } class _SortableAnimatedListState extends State<SortableAnimatedList> { final _listKey = GlobalKey<AnimatedListState>(); // 示例数据,priority数值越大优先级越高 List<Map<String, dynamic>> _items = List.generate(5, (index) => {"id": index, "name": "条目 $index", "priority": index}); // 提升条目优先级并重排 void _increasePriority(int index) { if (index == 0) return; // 已为最高优先级无需调整 final targetItem = _items[index]; // 更新优先级数值 targetItem['priority'] += 1; final oldIndex = index; // 重排后查找目标条目的新索引 _items.sort((a, b) => b['priority'].compareTo(a['priority'])); final newIndex = _items.indexWhere((e) => e['id'] == targetItem['id']); if (oldIndex == newIndex) return; // 触发旧位置元素的移除动画 _listKey.currentState?.removeItem( oldIndex, (context, animation) => _buildListItem(targetItem, animation), ); // 触发新位置元素的插入动画 _listKey.currentState?.insertItem(newIndex); } // 绑定动画的列表条目构建方法 Widget _buildListItem(Map<String, dynamic> item, Animation<double> animation) { return SizeTransition( sizeFactor: animation, child: SlideTransition( position: Tween<Offset>(begin: const Offset(1, 0), end: Offset.zero).animate(animation), child: ListTile( title: Text(item['name']), subtitle: Text("优先级:${item['priority']}"), trailing: IconButton( icon: const Icon(Icons.arrow_upward), onPressed: () => _increasePriority(_items.indexWhere((e) => e['id'] == item['id'])), ), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("可排序动画列表")), body: AnimatedList( key: _listKey, initialItemCount: _items.length, itemBuilder: (context, index, animation) => _buildListItem(_items[index], animation), ), ); } }
效果参考

注意事项
- 多元素同时重排场景下,遍历所有发生位置变化的元素依次调用移除+插入方法即可,动画会自动按队列播放
- 可根据需求自定义动画类型,除示例的平移交度过渡外,还可叠加淡入淡出、缩放等效果
内容的提问来源于stack exchange,提问作者secret
相关产品推荐
相关产品推荐

