前言
Flutter 自带的基础动画组件称之为隐式动画组件,小小统计了一下,会有几十个那么多,包括通用的动画构建类、特定的动画效果类以及封装好的动画组件。这么多,好处是想用的基本都有,不好的地方是记不住,找起来也不太方便。本篇特地整理了 Flutter 的隐式动画组件,方便各位 Flutter 爱好者(搬砖者)随时查看和使用。
AnimatedWidget
AnimatedWidget
是一个抽象类,可以通过 Animation
对象的值动态刷新每一帧从而实现动画效果。如果你想构建自己可复用的动画组件,那么可以使用 AnimatedWidget
,我们在
Flutter 实现风车加载动画组件
Flutter 实现 3D 动画效果详解
这两篇文章中就使用了AnimatedWidget
构建了一个风车加载指示动画组件。AnimatedWidget
的构造方法如下,其中 listenable
是一个抽象类 Listenable 对象,一般是 Animation
或 ChangeNotifier
。
const AnimatedWidget({
Key? key,
required this.listenable,
})
Animation
Animation
不算是一个组件,但是构建隐式动画组件都需要 Animation
对象来控制动画起止参数,动画曲线等。借助 Animation
,你可以基于 StatefulWidget
或 StatelessWidget
构建自己的动画类。我们在
Flutter 实现爱心三连动画
使用了 Animation
构建了爱心尺寸变化的动画。Animation
通常是依赖 AnimationController
组合实现动画效果。
AnimatedBuilder
AnimatedBuilder将动画效果和组件分离,从而使得动效可以应用与不同组件。如果在应用中一个动效会被用于多个不同的组件,那么 AnimatedBuilder
是首选。我们在
Flutter 入门与实战(九十六):使用 AnimatedBuilder 分离组件和动画,实现动效复用
做了AnimatedBuilder
的示例应用。AnimatedBuilder
的构造方法如下,animation
和 builder
是外部传入的,因此可以构造与组件分离的可复用的动画效果。
const AnimatedBuilder({
Key? key,
required Listenable animation,
required this.builder,
this.child,
})
AnimatedContainer
AnimatedContainer
是 Container
的动画替换组件,可以通过修改动画过程中的尺寸、对齐方式,tranform
参数等实现容器的动画效果。我们使用了 AnimatedContainer
实现了一个笑脸动画:
Flutter 复刻一个逼真的笑嘻嘻表情
AnimatedContainer
的构造方法如下,可以看到基本上所有的布局相关的属性都可以受动效控制。
AnimatedContainer({
Key? key,
this.alignment,
this.padding,
Color? color,
Decoration? decoration,
this.foregroundDecoration,
double? width,
double? height,
BoxConstraints? constraints,
this.margin,
this.transform,
this.transformAlignment,
this.child,
this.clipBehavior = Clip.none,
Curve curve = Curves.linear,
required Duration duration,
VoidCallback? onEnd,
})
AnimatedPositioned
AnimatedPositioned是 Stack
组件中的 Positioned
的动画替换组件。可以通过AnimatedPositioned
实现组件在 Stack
组件的位置,从而实现相对 Stack
组件的移动效果,譬如:
Flutter 模拟神舟十三号火箭发射动画
AnimatedPositioned
的构造方法如下,需要注意的是横向参数(left
、right
和 width
)、纵向参数(top
、bottom
和 height
)只能从3个里面选2个设置,否则会导致布局冲突。
const AnimatedPositioned({
Key? key,
required this.child,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
Curve curve = Curves.linear,
required Duration duration,
VoidCallback? onEnd,
})
AnimatedCrossFade
AnimatedCrossFade
用于两个组件切换,动效是渐现效果。同时若两个子组件的尺寸不同,可以使用 layoutBuilder
来平滑过渡尺寸的变化。两个子组件的动画曲线可以单独配置。最简单的应用就是更改两个要切换的子组件的显示,代码如下所示:
AnimatedCrossFade(
duration: const Duration(seconds: 3),
firstChild: const FlutterLogo(style: FlutterLogoStyle.horizontal, size: 100.0),
secondChild: const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
)
AnimatedCrossFade
的构造方法如下,其中 layoutBuilder
默认的组件布局构建方法。
const AnimatedCrossFade({
Key? key,
required this.firstChild,
required this.secondChild,
this.firstCurve = Curves.linear,
this.secondCurve = Curves.linear,
this.sizeCurve = Curves.linear,
this.alignment = Alignment.topCenter,
required this.crossFadeState,
required this.duration,
this.reverseDuration,
this.layoutBuilder = defaultLayoutBuilder,
})
AnimatedDefaultTextStyle
AnimatedDefaultTextStyle
用于文字样式动画效果,如果想自己控制字体变化过程(比如停留在中中间状态),可以使用DefaultTextStyleTransition 来完成。下面的动图是官网的效果,利用字体过渡的动画可以做品牌文字类的动画,可以加深用户的印象。
AnimatedDefaultTextStyle
的构造方法如下。
const AnimatedDefaultTextStyle({
Key? key,
required this.child,
required this.style,
this.textAlign,
this.softWrap = true,
this.overflow = TextOverflow.clip,
this.maxLines,
this.textWidthBasis = TextWidthBasis.parent,
this.textHeightBehavior,
Curve curve = Curves.linear,
required Duration duration,
VoidCallback? onEnd,
})
AnimatedList
AnimatedList
借助 AnimatedListState
可以实现插入和移出元素时的动画过渡效果,从而给列表的元素增加和删除的操作带来更好的反馈,提升用户体验。我们在 还在用 ListView?使用 AnimatedList 让列表元素动起来中介绍了如何使用 AnimatedList
。 整个的实现来说还是有点复杂,推荐在列表元素不多的时候使用。AnimatedList 的构造方法如下,其中关键的是 itemBuilder
接收了一个 animation
对象,因此可以用来完成插入动画。而对于删除元素,则需要借助 AnimatedListState
的 removeItem
方法完成。
const AnimatedList({
Key? key,
required this.itemBuilder,
this.initialItemCount = 0,
this.scrollDirection = Axis.vertical,
this.reverse = false,
this.controller,
this.primary,
this.physics,
this.shrinkWrap = false,
this.padding,
this.clipBehavior = Clip.hardEdge,
})
AnimatedModalBarrier
AnimatedModelBarrier
是 ModalBarrier
的替换,可以挡住它下层的组件,使得这些组件无法与用户交互,并且在组件上加一层颜色动画过渡遮罩。AnimatedModelBarrier
的构造方法如下。其中 dismissible
参数如果为 true
,则点击遮罩时会退出当前页面返回到上一页。
const AnimatedModalBarrier({
Key? key,
required Animation<Color?> color,
bool dismissible,
String? semanticsLabel,
bool? barrierSemanticsDismissible
})
可以使用AnimatedModalBarrier
做自定义弹层,当要弹出弹层时,使用 AnimatedModalBarrier
遮挡底层,然后再在它上层叠加新的组件就可以实现弹层的效果。下面是我们实现的一个示例,点击按钮后弹出一个遮罩层,然后遮罩上加了一个文字层。
AnimatedOpacity
AnimatedOpacity是透明度控制动画,可以控制子组件的透明度。这个就很好理解了,在动画过程中更改组件透明度。我们在Flutter 实现淡入淡出(Fade)动画效果 已经有过介绍了。
AnimatedPhysicalModel
控制组件的阴影、颜色、边框圆弧等物理模型,但组件自身的形状不发生改变。比如下图是官方给了一个更改阴影的例子,虽然组件自己没有变,但是因为阴影的变化,感觉却像是推开了一道缝隙一样,也挺有趣的。
AnimatedPhysicalModel
的构造方法如下,其中颜色和阴影颜色是通过两个布尔值 animateColor
和 animateShadowColor
决定是否要通过动画显示的。
const AnimatedPhysicalModel({
Key? key,
required Widget child,
required BoxShape shape,
Clip clipBehavior,
BorderRadius borderRadius,
required double elevation,
required Color color,
bool animateColor,
required Color shadowColor,
bool animateShadowColor,
Curve curve = Curves.linear,
required Duration duration,
VoidCallback? onEnd
})
下面是一段示例代码,通过更改elevation
属性实现Z 轴阴影的变化,同时做了颜色的过渡动画效果:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedPhysicalModel 动画'),
),
body: Center(
child: AnimatedPhysicalModel(
child: Container(
width: 300,
height: 300,
),
duration: Duration(seconds: 1),
color: _elevation == 0.0 ? Colors.blue : Colors.green,
animateColor: true,
animateShadowColor: true,
elevation: _elevation,
shape: BoxShape.circle,
shadowColor: Colors.blue[900]!,
curve: Curves.easeInOutCubic,
),
),
floatingActionButton: FloatingActionButton(
child: Text(
'Play',
style: TextStyle(
color: Colors.white,
),
textAlign: TextAlign.center,
),
onPressed: () {
setState(() {
_elevation = _elevation == 0 ? 10.0 : 0.0;
});
},
),
);
}
AnimatedSize
子组件的尺寸变化动画组件,通过尺寸的改变可以做放大缩小的效果,下面是官方的一个示例,点击组件的时候更改组件的尺寸,感觉是缩放一样。
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _updateSize(),
child: Container(
color: Colors.amberAccent,
child: AnimatedSize(
curve: Curves.easeIn,
duration: const Duration(seconds: 1),
child: FlutterLogo(size: _size),
),
),
);
}
总结
本篇列举了 Flutter 隐式动画的12个基础组件,普通的动画效果依赖这些组件基本就能搞定了。而如果需要转换类的动画效果需要使用 Transition
来支持,下篇岛上码农为你整理一下 Transition
类的动画组件。源码可以到这里下载:动画组件演示示例源码。