如何使用Flutter实现该括号式UI动效?附演示动图
Flutter 实现滚动触发式UI动效

你推测用ListView结合滚动位置触发动画的思路是对的,这类滚动过程中动态变换组件状态的效果,核心是通过ScrollController监听滚动偏移,结合子项在视口中的位置计算动画进度,再将进度映射到组件的变换属性上(比如缩放、位移、透明度)。
实现步骤:
- 初始化
ScrollController并监听滚动事件,实时获取滚动偏移量 - 遍历列表项,根据每个子项的位置计算其进入视口的比例(动画进度)
- 基于动画进度,动态调整子组件的外观参数,配合
AnimatedContainer或AnimatedBuilder实现平滑过渡
代码示例:
import 'package:flutter/material.dart'; class ScrollTriggerAnimPage extends StatefulWidget { const ScrollTriggerAnimPage({super.key}); @override State<ScrollTriggerAnimPage> createState() => _ScrollTriggerAnimPageState(); } class _ScrollTriggerAnimPageState extends State<ScrollTriggerAnimPage> { final ScrollController _scrollCtrl = ScrollController(); final Map<int, double> _itemProgress = {}; final double _itemHeight = 200; @override void initState() { super.initState(); _scrollCtrl.addListener(_updateItemProgress); } void _updateItemProgress() { setState(() { final viewportHeight = MediaQuery.of(context).size.height; for (int i = 0; i < 10; i++) { // 计算子项顶部相对于视口的位置 final itemTop = _scrollCtrl.offset + i * _itemHeight; // 计算动画进度:0(完全在视口下方)→1(完全进入视口) double progress = (viewportHeight - itemTop) / viewportHeight; progress = progress.clamp(0.0, 1.0); _itemProgress[i] = progress; } }); } @override void dispose() { _scrollCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( controller: _scrollCtrl, padding: const EdgeInsets.symmetric(vertical: 16), itemCount: 10, itemBuilder: (ctx, index) { final progress = _itemProgress[index] ?? 0.0; return AnimatedContainer( duration: const Duration(milliseconds: 120), height: _itemHeight, margin: EdgeInsets.symmetric( horizontal: 16 + (1 - progress) * 20, vertical: 8, ), transform: Matrix4.identity() ..scale(0.75 + progress * 0.25) ..translate(0, (1 - progress) * 30), child: Container( decoration: BoxDecoration( color: Colors.primaries[index % Colors.primaries.length], borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2 * progress), blurRadius: 8 * progress, offset: Offset(0, 4 * progress), ) ], ), child: Center( child: Text( "卡片 ${index + 1}", style: TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.w600, ), ), ), ), ); }, ), ); } }
自定义调整:
你可以根据动图的具体效果,修改动画参数:
- 调整
scale的范围实现不同的缩放幅度 - 修改
translate的数值控制位移距离 - 添加
opacity属性实现淡入淡出效果 - 调整
boxShadow参数实现阴影的动态变化
内容的提问来源于stack exchange,提问作者splurring
相关产品推荐
相关产品推荐

