如何链接多个控制器/动画?

时间:2017-10-12 23:53:10

标签: animation dart flutter

问题

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

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

  • 我尝试将Interval Widget用于多条曲线,但它没有提供平滑过渡。例如动画曲线的间隔(0.0,0.3),间隔(0.3,0.6),间隔(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),
          ],
        ),
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:7)

诀窍是你可以创建自己的补间。

简而言之,你想要的是一条平滑的曲线,从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);
  }
}