3、Curve动画曲线:Curve类、内置曲线、自定义Curve、曲线组合
动画曲线这东西,说白了就是控制动画「怎么动」的节奏感。你想想看,一个方块从A点移到B点,如果全程匀速,看起来就像机器人一样生硬。但如果你给它加一个「先快后慢」的曲线,立马就有了物理世界的真实感。
我个人习惯把Curve理解为「时间扭曲器」——它把0到1的线性时间,映射成不同的进度值。嗯,这个理解很重要,后面所有自定义曲线都基于这个思路。
3.1 Curve类:动画曲线的基类
在Flutter里,所有曲线都继承自Curve这个抽象类。它的核心方法就一个:
abstract class Curve {
double transform(double t);
}
这里的t是归一化后的时间,范围0.0到1.0。你传入0.5,它返回0.5,那就是线性。如果返回0.7,那就意味着前半程已经走了70%——说白了就是「加速」了。
核心要点:transform方法的输入输出都在[0,1]区间,但曲线可以超出这个范围(比如弹性曲线会超过1),Flutter会自动做clamp处理。
3.2 内置曲线:开箱即用的节奏库
Flutter内置了30多种曲线,我挑几个最常用的说说:
| 曲线名称 | 效果描述 | 适用场景 |
|---|---|---|
Curves.easeIn |
慢速开始,逐渐加速 | 物体离开视口 |
Curves.easeOut |
快速开始,逐渐减速 | 物体进入视口 |
Curves.easeInOut |
两头慢,中间快 | 对话框弹出/收起 |
Curves.bounceOut |
落地弹跳效果 | 物理碰撞反馈 |
Curves.elasticOut |
弹性拉伸效果 | 夸张的UI反馈 |
我在项目中遇到过一个问题:用bounceOut做列表项入场动画,结果弹跳幅度太大,看着很廉价。后来换成easeOutCubic,效果就舒服多了。所以啊,内置曲线虽好,但别盲目用,得看场景。
小技巧:用Curves.easeInOutBack做卡片翻转效果,会有一种「过头一点再回来」的弹性感,用户体验特别好。
3.3 自定义Curve:打造专属节奏
内置曲线不够用?那就自己写。实现自定义曲线有两种方式:
方式一:继承Curve类
class MyEaseOutCurve extends Curve {
@override
double transform(double t) {
// 这里实现一个三次方缓出
return 1 - (1 - t) * (1 - t) * (1 - t);
}
}
// 使用
final myCurve = MyEaseOutCurve();
说白了就是重写transform方法,输入时间t,输出进度值。数学公式随便你写,只要保证输入输出在合理范围内就行。
方式二:使用工厂方法
final customCurve = Curve((double t) {
// 实现一个「先快后慢再快」的节奏
if (t < 0.5) {
return 2 * t * t;
} else {
return 1 - 2 * (1 - t) * (1 - t);
}
});
这种方式更灵活,适合快速原型验证。我记得有一次做加载动画,需要一种「脉冲式」的缩放效果,用工厂方法几分钟就调出来了。
注意:自定义曲线要保证单调递增,否则动画会出现「倒流」现象。我曾经踩过这个坑,动画走到一半突然往回退,用户看着一脸懵。
3.4 曲线组合:1+1 > 2
单个曲线不够丰富?那就组合起来用。Flutter提供了几种组合方式:
级联组合
final combined = Curves.easeIn.chain(Curves.easeOut);
// 前半段用easeIn,后半段用easeOut
这个chain方法很有意思,它把两个曲线串联起来。前50%的时间用第一个曲线,后50%用第二个。我经常用它来做「先加速后减速」的复杂动画。
区间组合
final intervalCurve = Interval(0.3, 0.8, curve: Curves.easeOut);
// 动画只在30%到80%的时间段内执行
Interval类可以控制动画在哪个时间段生效。嗯,这个在制作「延迟入场」效果时特别有用——多个元素依次出现,每个元素只在自己的时间窗口内动。
阈值组合
final thresholdCurve = Threshold(0.5, curve: Curves.bounceOut);
// 前半段不动,后半段弹跳
这个用得少一些,但做「突然触发」的效果很合适。比如进度条到50%时突然弹一下,给用户一个视觉提醒。
实战经验:我做过一个列表加载动画,用Interval配合easeOut,让每个列表项依次从底部滑入。每个项延迟0.1秒启动,整体看起来就像波浪一样流畅。代码大概是这样:
final itemCurve = Interval(
index * 0.1,
index * 0.1 + 0.3,
curve: Curves.easeOut
);
曲线组合的精髓在于「控制节奏的粒度」。单个曲线只能控制整体,组合曲线可以控制每个时间段的细节。你想想看,一个复杂的交互动画,往往需要多种节奏配合——入场快、停留慢、退场更快,这些用组合曲线都能实现。
调试技巧:用Curve.toString()可以打印曲线的数学表达式。我经常在调试时打印出来,看看曲线在关键时间点的值是否合理。
最后说一句:曲线这东西,光看文档没用,得动手调。我建议你打开Flutter的AnimationController示例,把不同的曲线换上去跑一遍,感受一下每种曲线的「脾气」。嗯,调多了你自然就知道什么场景该用什么曲线了。