如何在Flutter中实现与参考视频匹配的流畅卡片滚动动画?
Flutter 流畅卡片滚动动画实现方案
核心思路:自定义滚动交互 + 动画控制器
放弃依赖第三方包,通过PageView结合Transform、AnimationController手动控制卡片的旋转、缩放、堆叠偏移,精准匹配参考效果。
关键实现步骤
- 基础布局搭建:用
PageView.builder作为滚动容器,设置viewportFraction小于1(比如0.8)让卡片露出前后部分,形成堆叠感。 - 动画参数绑定:监听
PageController的page值变化,将其映射为卡片的旋转角度(如-5 + 10 * (page - index))、缩放比例(如0.9 + 0.1 * (1 - abs(page - index)))、Y轴偏移量(如20 * abs(page - index))。 - 平滑过渡处理:用
AnimatedBuilder包裹卡片,将page值作为动画驱动源,确保所有变换参数实时平滑更新。 - 堆叠层级控制:通过
IndexedStack或Positioned结合层级控制,让当前卡片处于最上层,前后卡片依次降低层级。
示例核心代码片段
class CardScrollPage extends StatefulWidget { @override _CardScrollPageState createState() => _CardScrollPageState(); } class _CardScrollPageState extends State<CardScrollPage> { final PageController _pageController = PageController(viewportFraction: 0.8); double _currentPage = 0.0; @override void initState() { super.initState(); _pageController.addListener(() { setState(() { _currentPage = _pageController.page!; }); }); } @override Widget build(BuildContext context) { return Scaffold( body: PageView.builder( controller: _pageController, itemCount: 5, itemBuilder: (context, index) { final double offset = _currentPage - index; final double rotation = offset * 5; // 旋转角度可按需调整 final double scale = 1 - (offset.abs() * 0.1); // 缩放比例可按需调整 final double translateY = offset.abs() * 20; // Y轴偏移可按需调整 return Transform( transform: Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateY(rotation * pi / 180) ..scale(scale) ..translate(0, translateY), alignment: Alignment.center, child: Card( elevation: 8, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Container( width: double.infinity, height: 400, child: Center(child: Text('卡片 ${index + 1}')), ), ), ); }, ), ); } }
优化建议
- 调整
rotation、scale、translateY的系数,匹配参考图中的动画幅度; - 加入
CurvedAnimation使用如Curves.easeInOut的曲线,让动画过渡更自然; - 对非当前卡片降低透明度,增强堆叠层次感。
内容的提问来源于stack exchange,提问作者Mohammad Faizan
相关产品推荐
相关产品推荐

