蒙太奇
用于 Flutter 的组织动画组件
快速入门

// 1. Define your animations
const entrance = MontageAnimation(
key: 'entrance',
duration: Duration(seconds: 2),
);
const exit = MontageAnimation(
key: 'exit',
duration: Duration(seconds: 2),
);
class Home extends StatefulWidget {
const Home({
Key? key,
}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with TickerProviderStateMixin {
MontageController? controller;
@override
void initState() {
controller = MontageController(
vsync: this,
initialAnimation: entrance,
);
super.initState();
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: ValueListenableBuilder<MontageAnimation?>(
valueListenable: controller!.current,
builder: (context, current, child) => Text(current?.key ?? 'none'),
),
),
// 2. Wrap your animated widget in a `Montage` with its controller.
body: Montage(
controller: controller!,
child: BasicScene(),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
/// Plays this sequence of animations
controller!.play([
entrance,
exit,
]);
},
label: Text('Play'),
icon: Icon(Icons.video_call),
),
);
}
}
class BasicScene extends StatelessWidget {
const BasicScene({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 3. Use the motion widgets that defiens motions for each one of your animations
Motion(
motion: {
// You can use the provider motions or custom ones
entrance: Motions.combine([
Motions.rotate(startTurns: -1, endTurns: 0),
Motions.fadeIn,
]),
exit: Motions.combine([
Motions.rotate(startTurns: 0, endTurns: 1),
Motions.fadeOut,
]),
},
child: FlutterLogo(
size: 50,
),
),
MotionText(
text: 'Hello world',
style: TextStyle(
fontSize: 64,
color: Colors.black,
fontWeight: FontWeight.bold,
),
characterMotion: {
entrance: Motions.fadeFromTop(),
exit: Motions.fadeToTop(),
},
reversedCharacterAnimation: [exit],
wordMotion: {
entrance: Motions.fadeIn,
exit: Motions.fadeOut,
},
),
],
);
}
}
小部件
声明动画引用
您必须首先将场景的各种动画序列声明为MontageAnimation全局对象。
const entrance = MontageAnimation(
duration: Duration(seconds: 2),
);
const idle = MontageAnimation(
duration: Duration(seconds: 3),
);
const exit = MontageAnimation(
duration: Duration(seconds: 2),
);
蒙太奇
蒙太奇充当您的运动组件的根配置。它需要一个专用的控制器,允许触发动画。
class _HomeState extends State<Home> with TickerProviderStateMixin {
MontageController? controller;
@override
void initState() {
controller = MontageController(
vsync: this,
initialAnimation: entrance,
);
super.initState();
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Montage(
controller: controller!,
child: Scene(),
),
floatingActionButton: FloatingActionButton(
icon: Icon(Icons.video_call),
onPressed: () {
/// Plays this sequence of animations
controller!.play([
entrance,
exit,
entrance,
idle,
exit,
]);
},
),
);
}
}
运动
核心组件,可以为根Montage控制器的每个MotionAnimation以不同的方式为子widget设置动画。
Motion(
motion: {
entrance: Motions.fadeIn,
exit: Motions.fadeOut,
},
child: FlutterLogo(
size: 50,
),
)
交错动画
如果要逐步为一组小部件设置动画,可以使用Motion.staggered辅助方法。
提供了两个曲线:子项按原始顺序forward(向前)动画,或子项按反向顺序backwards(向后)动画。
如果您希望每个子项的动画在上一动画结束之前开始,您还可以配置overlap(重叠)。
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...Motion.staggered(
children: [
Text("FL"),
Text("UT"),
Text("TER"),
],
motion: (child, i, forward, backward) {
return {
entrance: Motions.curved(
forward,
Motions.combine([
Motions.rotate(startTurns: -1, endTurns: 0),
Motions.fadeIn,
Motions.scale(begin: 3, end: 1)
]),
),
exit: Motions.curved(
backward,
Motions.combine([
Motions.rotate(startTurns: 0, endTurns: -1),
Motions.fadeOut,
Motions.scale(begin: 1, end: 3)
]),
),
};
},
)
],
),
运动
内置
一组运动可以在motions.dart文件中找到。
自定义
运动只是一个组件构建器,它从当前的Animation<double>和要设置动画的子Widget接收。
Widget fadeIn(
BuildContext context,
MontageAnimation current,
Animation<double> animation,
Widget? child,
) {
return FadeTransition(
opacity: animation,
child: child,
);
}