3.3 动画两套工艺:隐式与显式


3.3 动画两套工艺:隐式与显式

本节摘要:界面的"动"分两种活儿:一种只是"值变了,希望它平滑过渡",另一种要"按编排推进、可暂停可反转"。前者交给隐式动画,后者交给显式动画的 AnimationController。本节给出两套工艺的选择标准与完整代码——账单删除时的收起动画、记账按钮的呼吸光晕都会当场做出来。

选工艺的判断题:谁控制时间线

动画系统的所有内容,围绕一道判断题:时间线的控制权在谁手里?

在数据手里——用隐式动画。 你的代码只改一个值(宽度、颜色、透明度),框架自动从旧值过渡到新值。AnimatedContainer、AnimatedOpacity、AnimatedPositioned、AnimatedSize 都是这个家族的,用起来与普通组件无异,只是属性变了会自己补间。适合:状态切换的过渡、布局微调、出现与消失。

在你手里——用显式动画。 AnimationController 是时间线本身:forward、reverse、repeat、stop,全由你调用;Animation 对象随着控制器的推进吐出插值,界面对它监听重建。适合:循环动效(加载光环、呼吸提示)、交错编排(多个元素依次入场)、与手势联动的跟手动画(拖动进度)。

一道实操判断题:动画要"响应一个状态变化"就用隐式,要"响应一个用户指令或循环"就用显式。 数据变了导致界面该过渡——隐式;用户点了播放、页面开始加载转圈——显式。模糊地带(点击触发一次位移动画)两者皆可,选隐式省代码,需要中途取消或反向时再升级成显式。

两套工艺共用同一套插值体系:曲线(Curves)决定节奏感,easeOut 前快后慢适合入场,easeInOut 适合双向过渡,elasticOut 的回弹留给强调性出现——曲线选对,观感提升立竿见影;时长上,界面过渡落在 150 到 400 毫秒之间最不惹人烦,超过半秒的过渡要让用户有理由等。

隐式动画:改值即动画

轻记账账单页的删除动画:账单行被删后,剩余行平滑上移补位,消失行的高度与透明度收拢。用 AnimatedContainer 与 AnimatedSize 组合即可,注意没有任何控制器

import 'package:flutter/material.dart'; class RemovableBillTile extends StatefulWidget { final String title; final double amount; const RemovableBillTile({super.key, required this.title, required this.amount}); @override State<RemovableBillTile> createState() => _RemovableBillTileState(); } class _RemovableBillTileState extends State<RemovableBillTile> { bool _dismissed = false; void _remove() { setState(() => _dismissed = true); // 只改数据,过渡交给 AnimatedXxx Future.delayed(const Duration(milliseconds: 300), () { if (mounted) setState(() {}); // 触发从列表中真正移除 }); } @override Widget build(BuildContext context) { return AnimatedSize( duration: const Duration(milliseconds: 250), curve: Curves.easeOut, child: _dismissed ? const SizedBox(width: double.infinity) : AnimatedOpacity( duration: const Duration(milliseconds: 200), opacity: _dismissed ? 0 : 1, child: ListTile( title: Text(widget.title), trailing: Text('¥${widget.amount}'), onLongPress: _remove, ), ), ); } }

这段代码里没有任何一行动画 API 的"控制"语句——动画是数据变化的必然结果。隐式动画的哲学就在这里:把补间逻辑下沉到组件内部,业务代码只关心状态。代价是编排能力有限:想"先位移、后淡出、同时别的行等一等",隐式动画就力不从心了。

显式动画:控制器在手的完整形态

记账页需要主按钮有呼吸光晕提示用户"点这里开始记账"——循环动效,必须显式。AnimationController 的标准生命周期姿势:

import 'package:flutter/material.dart'; class PulsingFab extends StatefulWidget { const PulsingFab({super.key, this.onPressed}); final VoidCallback? onPressed; @override State<PulsingFab> createState() => _PulsingFabState(); } class _PulsingFabState extends State<PulsingFab> with SingleTickerProviderStateMixin { late final AnimationController _ctrl; late final Animation<double> _scale; @override void initState() { super.initState(); _ctrl = AnimationController( vsync: this, // 帧同步:只在可见时推进 duration: const Duration(milliseconds: 900), lowerBound: 0.96, upperBound: 1.04, )..repeat(reverse: true); // 循环往复 _scale = CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut); } @override void dispose() { _ctrl.dispose(); // 与订阅一样:用了就还 super.dispose(); } @override Widget build(BuildContext context) { return ScaleTransition( scale: _scale, child: FloatingActionButton.extended( onPressed: widget.onPressed, icon: const Icon(Icons.add), label: const Text('记一笔'), ), ); } }

四个部件各就各位:Controller 是时间线(推进、方向、速度);vsync 是帧闸门——Tickers 绑定到组件可见性,页面切走时动画自动暂停,省电也省帧;CurvedAnimation 是节奏Transition 组件是消费者,把每帧插值转成变换。纪律只有一条:控制器必须 dispose,泄漏的控制器会在页面关闭后继续驱动重建,轻则耗电,重则"setState after dispose"崩溃。

交错编排是显式动画的招牌菜。多张卡依次入场,只需给每张卡一个带延迟的 Interval:

// Staggered 动画:总时长 600 毫秒,第 i 张卡占其中一段 late final Animation<double> _slide; _slide = CurvedAnimation( parent: _ctrl, curve: Interval(0.15 * i, 0.15 * i + 0.6, curve: Curves.easeOut), );

同一条时间线被切成多段,每段管一张卡——"编排"由此而来。想反向退场,控制器一记 reverse,全部卡片按原路返回,这就是控制权在你手里的含义。

动画与性能:动得优雅也别动出账单

动画期间界面每帧都在重建与绘制,是渲染管线的常客。三条省钱习惯从现在养成:变换与透明度类动画(位移、缩放、透明度)只影响合成阶段,开销远低于改变布局尺寸的动画——能用 ScaleTransition 就别用 AnimatedSize 反复触发布局;循环动画在页面不可见时依赖 vsync 自动暂停,别自己另开 Timer 驱动;动画嵌在长列表里时,给动画区域套 RepaintBoundary,把重绘圈在局部(第 6 章会给出量化对比)。

本节要点回顾

  • 判断题:时间线归数据管用隐式(AnimatedXxx 改值即动画),归指令或循环管用显式(AnimationController);
  • 隐式动画零控制器,适合状态过渡;交错、反转、跟手必须显式;
  • 显式四件套:Controller 时间线、vsync 帧闸门、CurvedAnimation 节奏、Transition 消费者;
  • 控制器必须 dispose,vsync 让页面切走时动画自动停;
  • 过渡时长 150 到 400 毫秒为宜,变换与透明度动画比布局动画便宜。

界面的形与动都有了,还差"气质"——下一节用主题系统统一轻记账的观感,并让它在一端像 Material、另一端像 Cupertino。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U