如何重新启动在完成之前停止但具有不同参数的动画

时间:2019-07-03 17:54:24

标签: flutter dart

我有一个动画,其中两个容器相互碰撞。我希望容器以动画的方式回退到各自的起始偏移量。容器沿不同的路径和持续时间移动。

enter image description here

如动画gif所示,绿色和红色容器发生碰撞并跳回到其起始偏移位置,而不是向后滑动。

这是我用来制作GIF的代码,在我的实际代码中,我使用矩形相交检查容器何时碰撞。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  List<AnimationController> _controller = List(2);
  List<Animation<Offset>> _animation = List(2);
  List<Tween<Offset>> tween = List(2);

  @override
  void initState() {
    super.initState();
    tween[0] = Tween(begin: Offset(0, 10), end: Offset(200, 10));
    tween[1] = Tween(begin: Offset(200, 10), end: Offset(0, 10));
    for (int i = 0; i < 2; i++) {
      _controller[i] =
          AnimationController(vsync: this, duration: Duration(seconds: 1));

      _animation[i] = tween[i].animate(_controller[i])
        ..addListener(
          () {
            setState(
              () {
                print(
                    '${_animation[0].value.dx.toInt()}:${_animation[0].value.dy.toInt()} ${_animation[1].value.dx.toInt()}:${_animation[1].value.dy.toInt()}');
                if (((_animation[0].value.dx) / 2).round() ==
                    ((_animation[1].value.dx) / 2).round()) {
                  _controller[0].stop();
                  _controller[1].stop();

                  _controller[0].reset();
                  _controller[1].reset();

                  Future.delayed(Duration(milliseconds: 100)).then((_) {
                    tween[0] = Tween(
                        begin: Offset(
                            _animation[0].value.dx, _animation[0].value.dy),
                        end: Offset(0, 10));
                    tween[1] = Tween(
                        begin: Offset(
                            _animation[1].value.dx, _animation[1].value.dy),
                        end: Offset(200, 10));

                    _animation[0] = tween[0].animate(_controller[0]);
                    _animation[1] = tween[1].animate(_controller[1]);

                    _controller[0].forward();
                    _controller[1].forward();
                  });
                }
              },
            );
          },
        );
    }

    WidgetsBinding.instance.addPostFrameCallback(
      (_) => _afterLayout(),
    );
  }

  void _afterLayout() {
    for (int i = 0; i < 2; i++) {
      _controller[i].forward();
    }
  }

  @override
  void dispose() {
    super.dispose();
    for (int i = 0; i < 1; i++) {
      _controller[i].dispose();
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("collision"),
        ),
        body: Column(
          children: <Widget>[
            Expanded(
              child: Stack(
                children: <Widget>[
                  Container(
                    width: double.infinity,
                    height: double.infinity,
                  ),
                  Positioned(
                    left: _animation[0] != null ? _animation[0].value.dx : 0,
                    top: _animation[0] != null ? _animation[0].value.dy : 0,
                    child: Container(
                      width: 50,
                      height: 50,
                      color: Colors.red,
                    ),
                  ),
                  Positioned(
                    left: _animation[1] != null ? _animation[1].value.dx : 0,
                    top: _animation[1] != null ? _animation[1].value.dy : 0,
                    child: Container(
                      width: 50,
                      height: 50,
                      color: Colors.green,
                    ),
                  ),
                ],
              ),
            ),
            RaisedButton(
              onPressed: () {
                _controller[0].reset();
                _controller[1].reset();

                tween[0] = Tween(begin: Offset(0, 10), end: Offset(200, 10));
                tween[1] = Tween(begin: Offset(200, 10), end: Offset(0, 10));

                _controller[0].duration = Duration(seconds: 1);
                _controller[1].duration = Duration(seconds: 1);

                _animation[0] = tween[0].animate(_controller[0]);
                _animation[1] = tween[1].animate(_controller[1]);

                _controller[0].forward();
                _controller[1].forward();
              },
              child: Text("Animate"),
            )
          ],
        ),
      ),
    );
  }
}

我希望容器通过动画平滑地滑回到其各自的起始偏移。

1 个答案:

答案 0 :(得分:1)

我会在这里添加一些说明,以帮助其他人。

颤动中的动画由AnimationController控制。您可以使用单个AnimationController控制一个或多个动画(如果要同时触发动画,则可以使用相同的控制器)。

现在,要启动动画(或链接到同一控制器的所有动画),可以使用forward()方法。 forward()方法接受一个参数,该参数指定动画应从哪个点继续播放,该参数值介于0 ... 1之间。

如果要向后制作动画,则控制器具有一个称为reverse()的方法,该方法将以相反的顺序执行动画。同样,该方法接受的参数值为0到1,如果未指定任何参数,动画将从最后一个状态“反转”。

请注意,要制作反向动画,您应该调用控制器上的reset()reset()方法会将控制器的所有值设置为初始值。