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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:48:04