Flutter loader:同时调整大小和旋转

Flutter loader: resize and rotate at the same time

我刚接触Flutter,想做一个定制的loader,但是找不到解决方案。当用户点击一个按钮并开始一些操作时,我想显示一个自定义的小部件(基本上是一个加载程序,通知用户操作已经开始)弹出到屏幕中央并增加大小(从 0x0到 300x300),同时旋转。当它达到最大尺寸 (300x300) 时,我希望它在旋转时缩小回 0x0 和 hide/disappear 的尺寸。 这个动画应该需要 2 秒。如果2秒后操作没有完成,我想重新开始播放动画。

您可以非常轻松地创建自己的动画。使用 AnimationAnimationController 你基本上可以做任何你能想到的事情。

如果您想更深入地了解使用 Flutter 制作动画,请观看此视频 Complex UIs

要实现您的要求,您可以使用无状态小部件构建加载指示器。

这是一个interactive example

class MyLoadingIndicator extends StatefulWidget {
  final Widget child;
  const MyLoadingIndicator({
    @required this.child,
    Key key,
  }) : super(key: key);

  @override
  _MyLoadingIndicatorState createState() => _MyLoadingIndicatorState();
}

class _MyLoadingIndicatorState extends State<MyLoadingIndicator> with TickerProviderStateMixin {
  AnimationController rotateController;
  Animation<double> rotateAnimation;
  AnimationController scaleController;
  Animation<double> scaleAnimation;

  @override
  void initState() {
    super.initState();
    rotateController = AnimationController(
      duration: const Duration(seconds: 1),
      reverseDuration: const Duration(seconds: 1),
      vsync: this,
    );

    rotateAnimation = CurvedAnimation(parent: rotateController, curve: Curves.linear);
    rotateController.repeat(
      min: 0,
      max: 1,
      period: Duration(seconds: 2),
    );
    scaleController = AnimationController(
      duration: const Duration(seconds: 1),
      reverseDuration: const Duration(seconds: 1),
      vsync: this,
    );

    scaleAnimation = CurvedAnimation(parent: scaleController, curve: Curves.linear);
    scaleController.repeat(
      min: 0,
      max: 1,
      period: Duration(seconds: 2),
      reverse: true,
    );
  }

  @override
  void dispose() {
    rotateController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return RotationTransition(
      turns: rotateAnimation,
      child: ScaleTransition(
        scale: scaleAnimation,
        child: Container(
          height: 300,
          width: 300,
          color: Colors.red,
          child: widget.child,
        ),
      ),
    );
  }
}