animation - 如何链接多个 Controller /动画?

标签 animation dart flutter

问题

我在 flutter 中制作了一个椭圆加载动画,但必须在所有三个不同的 Controller 上使用 Timer。 (参见下面的示例...)

是否有任何小部件可以帮助链接三个不同的动画?

  • 我尝试对多条曲线使用 Interval 小部件,但它没有提供平滑的过渡。例如Interval(0.0, 0.3), Interval(0.3, 0.6), Interval(0.6, 0.9) 动画曲线。

示例

示例代码

import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'dart:async';

void main() {
  runApp(
    new MaterialApp(
      home: new Scaffold(
        body: new CircleLoader(),
      )
    )
  );
}

class CircleLoader extends StatefulWidget {
  @override
  _CircleLoaderState createState() => new _CircleLoaderState();
}

class _CircleLoaderState extends State<CircleLoader>
    with TickerProviderStateMixin {
  Animation<double> animation;
  Animation<double> animation2;
  Animation<double> animation3;
  AnimationController controller;
  AnimationController controller2;
  AnimationController controller3;
  int duration = 1000;
  Widget circle = new Container(
    height: 10.0,
    width: 10.0,
    decoration: new BoxDecoration(
      shape: BoxShape.circle,
      color: Colors.grey[300],
    ),
  );

  @override
  initState() {
    super.initState();
    controller = new AnimationController(
        duration: new Duration(milliseconds: duration), vsync: this);
    controller2 = new AnimationController(
        duration: new Duration(milliseconds: duration), vsync: this);
    controller3 = new AnimationController(
        duration: new Duration(milliseconds: duration), vsync: this);

    final CurvedAnimation curve =
        new CurvedAnimation(parent: controller, curve: Curves.easeInOut);
    final CurvedAnimation curve2 =
        new CurvedAnimation(parent: controller2, curve: Curves.easeInOut);
    final CurvedAnimation curve3 =
        new CurvedAnimation(parent: controller3, curve: Curves.easeInOut);

    animation = new Tween(begin: 0.85, end: 1.5).animate(curve)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          controller.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller.forward();
        }
      });
    animation2 = new Tween(begin: 0.85, end: 1.5).animate(curve2)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          controller2.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller2.forward();
        }
      });
    animation3 = new Tween(begin: 0.85, end: 1.5).animate(curve3)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          controller3.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller3.forward();
        }
      });

    controller.forward();
    new Timer(const Duration(milliseconds: 300), () {
      controller2.forward();
    });
    new Timer(const Duration(milliseconds: 600), () {
      controller3.forward();
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        width: 100.0,
        height: 50.0,
        color: Colors.grey,
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new ScaleTransition(scale: animation, child: circle),
            new ScaleTransition(scale: animation2, child: circle),
            new ScaleTransition(scale: animation3, child: circle),
          ],
        ),
      ),
    );
  }
}

最佳答案

诀窍在于您可以创建自己的补间。

简而言之,你想要的是一条平滑的曲线,从 0 到 1,然后从 1 到 0 平滑。您可以将其同化为 (sin(t * 2 * PI) + 1)/2,其中 0 <= t <= 1 然后为每个 cicles 延迟该曲线。

class TestTween extends Tween<double> {
  final double delay;

  TestTween({double begin, double end, this.delay}) : super(begin: begin, end: end);

  @override
  double lerp(double t) {
    return super.lerp((sin((t - delay) * 2 * PI) + 1) / 2);
  }
}

允许做什么

_controller = new AnimationController(
  vsync: this,
  duration: const Duration(seconds: 2),
)..repeat();

不必添加动画监听器并反转动画。

最终结果是

class CircleLoader extends StatefulWidget {
  @override
  _CircleLoaderState createState() => new _CircleLoaderState();
}

class _CircleLoaderState extends State<CircleLoader>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat();
  }

  @override
  dispose() {
    _controller.dispose();
    super.dispose();
  }

  buildCircle(double delay) {
    return new ScaleTransition(
      scale: new TestTween(begin: .85, end: 1.5, delay: delay)
          .animate(_controller),
      child: new Container(
        height: 10.0,
        width: 10.0,
        decoration: new BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.grey[300],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        width: 100.0,
        height: 50.0,
        color: Colors.grey,
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            buildCircle(.0),
            buildCircle(.2),
            buildCircle(.4),
          ],
        ),
      ),
    );
  }
}

class TestTween extends Tween<double> {
  final double delay;

  TestTween({double begin, double end, this.delay})
      : super(begin: begin, end: end);

  @override
  double lerp(double t) {
    return super.lerp((sin((t - delay) * 2 * PI) + 1) / 2);
  }
}

关于animation - 如何链接多个 Controller /动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46720549/

相关文章:

dart - Flutter Expansion Tile -- 标题颜色变化,尾随动画箭头颜色变化

Flutter:将文件(图像)裁剪为圆形

Flutter 遍历 List 并访问索引

firebase - Flutter Firestore StreamTransformer DocumentSnapshot错误

jQuery悬停()不适用于绝对定位的元素和动画

javascript - 滚动淡入会淡化所有内容,而不是 1 乘 1

java - Flutter - 无法将 MethodChannel 与 Firebase onBackgroundMessage 一起使用

flutter - 在 Flutter 中,如何检查是鼠标设备还是触摸设备?

html - 如何在一个标签中有两个 css 动画

css - SVG 和 CSS 中的简单速度计动画