我已经关注了关于flutter.io的各种动画教程(补间,交错,过渡等),而且效果很好。
我想探索的是如何根据UI对象的组成实际制作自定义动画。
让我们举一个简单的例子,一个暂停->播放动画。
首先,我们有一个Pause图标,两个垂直条。
我想说
这看起来像是播放按钮,不再是暂停按钮。
我将如何实现这种自定义动画?我假设我不能使用图标类。而且我很确定我不应该使用Widget来做到这一点,而只是将它们移动。
我将在哪里开始探索动画的这种精度?
答案 0 :(得分:4)
@Alaric的答案将您指向了几个软件包,但并没有真正说明为什么要使用它们。
眼前的问题是,您正在谈论的动画在其实际工作方式上有些复杂。有很多项目会随着时间的变化而变化,甚至有可能变成更大的项目。
您可以采用两种方法来解决此问题。第一种是使用外部动画工具来创建此动画,无论动画工具必须使用哪个功能来进行项目更改和合并。然后,一旦获得满意的动画,就必须以某种方式将其导入到项目中。这就是fluttie和flare_flutter插件的加入-如果您使用Aftereffects,则可以使用Lottie导出文件,然后使用fluttie插件显示文件。 Flare稍微有点简单,因为它意味着颤动,但是您仍然可以在外部创建动画,然后将文件添加到要渲染的资产中。
另一种方法是自己制作动画。这涉及三件事:
如果使用GlobalKey来访问动画并公开开始/停止方法,则包含动画的窗口小部件也可能是控制器,但这有点混乱。最好有一个外部对象作为控制器-而且您甚至可以按原样使用AnimationController,尽管这样做不太“干净”。
如果不传递它,则可能在控件中或从类或控件开始和停止的小部件中有一个AnimationController。从本质上讲,它将只是从0到1并返回,并负责重建CustomPainter(可能使用AnimatedBuilder)。
这是一个非常基本的示例,因为手势检测发生在小部件内,因此不需要外部控制器。请注意,我不会在每次设置“ started”成员时都调用setState,因为我实际上不希望它在更改时进行重建。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: StartStop(),
),
),
);
}
}
class StartStop extends StatefulWidget {
@override
StartStopState createState() {
return new StartStopState();
}
}
class StartStopState extends State<StartStop> with TickerProviderStateMixin<StartStop> {
bool started = false;
AnimationController animationController;
@override
void initState() {
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
started ? animationController.forward() : animationController.reverse();
started = !started;
},
child: SizedBox(
width: 100,
height: 100,
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return CustomPaint(
painter: StartStopPainter(animationController.value),
size: Size.infinite,
child: child,
);
},
),
),
);
}
}
class StartStopPainter extends CustomPainter {
final double percentAnimated;
StartStopPainter(this.percentAnimated) : assert(percentAnimated >= 0 && percentAnimated <= 1);
@override
void paint(Canvas canvas, Size size) {
var pausePaint = Paint()..color = Colors.black.withOpacity(1 - percentAnimated);
canvas.drawRect(Rect.fromLTRB(20, 10, 40, 90), pausePaint);
canvas.drawRect(Rect.fromLTRB(60, 10, 80, 90), pausePaint);
var playPaint = Paint()..color = Colors.black.withOpacity(percentAnimated);
canvas.drawPath(Path()..addPolygon([Offset(20, 10), Offset(20, 90), Offset(80, 50)], true), playPaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
我将保留动画的实际自定义部分(将矩形更改为三角形等)。只需使用输入percentAnimated
来确定要绘制的路径或多边形,而不是使用不透明度和一些其他的绘制调用。
答案 1 :(得分:2)
有2个动画程序包可以帮助您:Flare和Lottie
讽刺: 需要后效应之类的动画软件。
包装:https://pub.dartlang.org/packages/fluttie
耀斑: 带有自己的免费动画软件:https://www.2dimensions.com/about-flare 包裹:https://pub.dartlang.org/packages/flare_flutter
如果您不仅仅在他们的编辑器中工作,而且从我的理解来看,Flare的运行效率和Fluttie都更高,那么Flare确实是个bug。 Fluttie更稳定,但价格更高。随便挑。