因此,我试图在Flutter中创建一个动画,每次用户按下按钮时,动画都需要不同的结果。
我已经根据Flutter Animations tutorial实现了以下代码,并创建了一个更新它的函数。
class _RoulettePageWidgetState extends State<RoulettePageWidget>
with SingleTickerProviderStateMixin {
Animation<double> _animation;
Tween<double> _tween;
AnimationController _animationController;
int position = 0;
@override
void initState() {
super.initState();
_animationController =
AnimationController(duration: Duration(seconds: 2), vsync: this);
_tween = Tween(begin: 0.0, end: 100.0);
_animation = _tween.animate(_animationController)
..addListener(() {
setState(() {});
});
}
void setNewPosition(int newPosition) {
_tween = Tween(
begin: 0.0,
end: math.pi*2/25*newPosition);
_animationController.reset();
_tween.animate(_animationController);
_animationController.forward();
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Center(
child: Transform.rotate(
angle: _animationController.value,
child: Icon(
Icons.arrow_upward,
size: 250.0,
),
)),
Expanded(
child: Container(),
),
RaisedButton(
child: Text('SPIN'),
onPressed: () {
setState(() {
setNewPosition(math.Random().nextInt(25));
});
},
)
],
)
);
}
}
您可以看到我正在更新_tween
的{{1}}和begin:
,但这似乎并没有改变动画。
那么,每当用户按下按钮时,我该怎么做才能创建一个“不同的”动画?
通常的想法是使动画以随机的新值彼此叠加,例如:
所以我想知道是否可以更新动画,还是应该每次创建一个新动画? 我想到的另一件事是跟踪位置并每次都使用相同的动画(0.0-> 100.0)占转移的百分比。
因此,与其从10-> 15创建一个新动画,不如做如下事情:
end:
答案 0 :(得分:8)
我将略微跳过您的代码,专注于您真正要问的问题:
通常的想法是使动画以随机的新值彼此叠加,例如:
第一次旋转:0-> 10
第二次旋转:10-> 13
第三旋转:13-> 18
...等等
使用这样的显式动画,您需要三个对象:
一个 controller ,这是一种特殊的动画,它简单地从其下限到上限(两个都是倍数,通常为0.0和1.0)线性生成值。您可以控制动画的流程-向前运行,反向,停止或重置动画。
一个补间,它不是 动画,而是 Animatable 。补间定义了两个值之间的插值,甚至不必是数字。它在幕后实现了一个transform
方法,该方法将获取动画的当前值并吐出您要使用的实际值:另一个数字,颜色,线性渐变甚至整个小部件。这就是生成旋转角度时应使用的方法。
一个动画,它是您实际上要使用其值的动画(因此,您可以在其中获取要构建的值)。您可以通过为补间动画设置父动画来进行转换-这可以直接作为您的控制器,也可以是您在其上构建的其他某种动画(例如CurvedAnimation,它可以使您缓和或弹性/弹性曲线,依此类推)。 Flutter的动画可以通过这种方式进行高度组合。
您的代码失败的主要原因是,您实际上并未使用在构建方法中创建的顶级动画,并且每次调用{{1 }}。您可以对多个动画“周期”使用相同的补间和动画-只需更改现有补间的setNewPosition
和begin
属性,它就会冒出动画。最终结果如下:
end
希望有帮助!
答案 1 :(得分:0)
在工作时,您实际上并不想像@filleduchaos所述在布局中 制作这些动画。
这是未优化的,因为您要重建的动画远远超过了动画。写自己很痛苦。
您将为此使用AnimatedWidget
系列。他们分为两个
种类:
第一个是消耗Animation
并听取它的低层,这样您就不必那么丑了:
..addListener(() {
setState(() {});
});
第二个处理其余部分:AnimationController
,TickerProvider
和Tween
。
这使动画的使用变得更加容易,因为它几乎是完全自动的。
在您的情况下,旋转示例如下:
class RotationExample extends StatefulWidget {
final Widget child;
const RotationExample({
Key key,
this.child,
}) : super(key: key);
@override
RotationExampleState createState() {
return new RotationExampleState();
}
}
class RotationExampleState extends State<RotationExample> {
final _random = math.Random();
double rad = 0.0;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _rotate,
child: AnimatedTransform(
duration: const Duration(seconds: 1),
alignment: Alignment.center,
transform: Matrix4.rotationZ(rad),
child: Container(
color: Colors.red,
height: 42.0,
width: 42.0,
),
),
);
}
void _rotate() {
setState(() {
rad = math.pi * 2 / 25 * _random.nextInt(25);
});
}
}
更容易吧?
具有讽刺意味的是,Flutter忘记提供AnimatedTransform
(尽管我们还有很多其他人!)。但是不用担心,我为您做到了!
AnimatedTransform
实现如下:
class AnimatedTransform extends ImplicitlyAnimatedWidget {
final Matrix4 transform;
final AlignmentGeometry alignment;
final bool transformHitTests;
final Offset origin;
final Widget child;
const AnimatedTransform({
Key key,
@required this.transform,
@required Duration duration,
this.alignment,
this.transformHitTests = true,
this.origin,
this.child,
Curve curve = Curves.linear,
}) : assert(transform != null),
assert(duration != null),
super(
key: key,
duration: duration,
curve: curve,
);
@override
_AnimatedTransformState createState() => _AnimatedTransformState();
}
class _AnimatedTransformState
extends AnimatedWidgetBaseState<AnimatedTransform> {
Matrix4Tween _transform;
@override
void forEachTween(TweenVisitor<dynamic> visitor) {
_transform = visitor(_transform, widget.transform,
(dynamic value) => Matrix4Tween(begin: value));
}
@override
Widget build(BuildContext context) {
return Transform(
alignment: widget.alignment,
transform: _transform.evaluate(animation),
transformHitTests: widget.transformHitTests,
origin: widget.origin,
child: widget.child,
);
}
}
我将提交拉取请求,以便将来不再需要这段代码。