如何在Flutter中实现堆叠卡片滚动动画及对应UI效果?
Flutter堆叠卡片滚动动画实现方案
核心思路
通过ScrollController监听滚动偏移量,结合Transform和Opacity组件,实时计算每个卡片的缩放、位移、透明度参数,模拟堆叠滚动的视觉效果。主要依赖ListView(或横向ListView)作为滚动容器,配合Positioned控制卡片初始堆叠位置。
具体实现步骤
- 定义卡片数据模型:封装卡片所需的标题、描述、颜色等信息
- 初始化滚动控制器:监听滚动偏移量,用于计算卡片的动画参数
- 构建堆叠列表:使用
ListView.builder生成卡片,每个卡片通过Transform应用动态变换 - 计算动画参数:根据滚动偏移量,实时计算卡片的缩放比例、位移距离和透明度
- 优化视觉层次:通过调整阴影、堆叠间距,增强卡片的堆叠立体感
完整代码示例
import 'package:flutter/material.dart'; class CardItem { final String title; final String description; final Color color; CardItem({required this.title, required this.description, required this.color}); } class StackedCardsScreen extends StatefulWidget { const StackedCardsScreen({super.key}); @override State<StackedCardsScreen> createState() => _StackedCardsScreenState(); } class _StackedCardsScreenState extends State<StackedCardsScreen> { final ScrollController _scrollController = ScrollController(); final List<CardItem> _cards = [ CardItem(title: "卡片1", description: "这是第一张堆叠卡片", color: Colors.blueAccent), CardItem(title: "卡片2", description: "这是第二张堆叠卡片", color: Colors.orangeAccent), CardItem(title: "卡片3", description: "这是第三张堆叠卡片", color: Colors.greenAccent), CardItem(title: "卡片4", description: "这是第四张堆叠卡片", color: Colors.purpleAccent), ]; final double _cardHeight = 280; final double _stackOffset = 80; // 上下卡片的重叠间距 @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("堆叠卡片滚动")), body: ListView.builder( controller: _scrollController, padding: EdgeInsets.only(top: 100, bottom: 100 + _stackOffset), itemCount: _cards.length, itemBuilder: (context, index) { return _buildStackedCard(index); }, ), ); } Widget _buildStackedCard(int index) { final double cardTop = index * (_cardHeight - _stackOffset); final double scrollOffset = _scrollController.hasClients ? _scrollController.offset : 0; // 计算滚动进度(0=未滚动,1=完全滚出视野) double scrollRatio = (scrollOffset - cardTop) / _cardHeight; scrollRatio = scrollRatio.clamp(0.0, 1.0); // 动画参数:可根据需求调整系数 final double scale = 1 - (0.2 * scrollRatio); // 缩放从1到0.8 final double translateY = _stackOffset * scrollRatio; // Y轴位移从0到_stackOffset final double opacity = 1 - (0.4 * scrollRatio); // 透明度从1到0.6 return Positioned( top: cardTop, left: 20, right: 20, height: _cardHeight, child: Transform( transform: Matrix4.identity() ..translate(0, translateY) ..scale(scale), alignment: Alignment.topCenter, child: Opacity( opacity: opacity, child: Card( elevation: 8 - (6 * scrollRatio), // 滚动时降低阴影 shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), color: _cards[index].color, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _cards[index].title, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white), ), const SizedBox(height: 12), Text( _cards[index].description, style: const TextStyle(fontSize: 16, color: Colors.white70), ), ], ), ), ), ), ), ); } }
自定义调整技巧
- 修改
_cardHeight和_stackOffset可调整卡片尺寸与堆叠密度 - 调整
scale、translateY、opacity的系数,可控制动画的幅度和快慢 - 若需横向堆叠滚动,将
ListView的scrollDirection设为Axis.horizontal,并把translateY改为translateX - 可添加卡片的旋转动画,在
Matrix4中加入rotateZ参数(如..rotateZ(0.02 * scrollRatio))增强动态效果
内容的提问来源于stack exchange,提问作者Hetal
相关产品推荐
相关产品推荐

