颤动动画如何逐渐淡出/淡出

时间:2017-09-28 18:10:55

标签: dart flutter

我开始在Flutter上尝试制作一个在连续淡入和淡出时旋转的动画。到目前为止旋转工作,但我有褪色效果的困难。小部件将逐渐变为透明,但在一次旋转之后,它会再次变为透明状态之前跳回到不透明状态。我试图解决这个问题,但我似乎无法弄清楚如何解决这个问题。使用.forward().reverse()并不起作用,但我可能错误地实施了不透明动画。

class AnimatedLoader extends AnimatedWidget {
  static final _opacityTween = new Tween<double>(begin: 1.0, end: 0.3);

  AnimatedLoader({
    Key key,
    this.alignment: FractionalOffset.center,
    Animation<double> turns,
    Animation<double> animation,
    this.child,
  }) : super(key: key, listenable: turns);

  Animation<double> get turns => listenable;

  final FractionalOffset alignment;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    final double turnsValue = turns.value;
    final Matrix4 transform = new Matrix4.rotationZ(turnsValue * math.PI * 2.0);
    return new Transform(
      alignment: alignment,
      transform: transform,
      child: new Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: child,
      )
    );
  }
}

class AppLoader extends StatefulWidget {
  AppLoaderState createState() => new AppLoaderState();
}

class AppLoaderState extends State<AppLoader> with TickerProviderStateMixin {
  AnimationController _controller;
  AnimationController _controllerOp;
  Animation<double> animation;

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

    _controllerOp = new AnimationController(
      duration: const Duration(milliseconds: 800),
      vsync: this,
    );
    animation = new Tween(begin: 0.0, end: 300.0).animate(_controllerOp);

    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _controllerOp.reverse();
      } else if (status == AnimationStatus.dismissed) {
        _controllerOp.forward();
      }
    });
    _controllerOp.forward();
  }

  @override
  Widget build(BuildContext context) {
    return new Center (
      child: new AnimatedLoader(
        turns: _controller,
        alignment: FractionalOffset.center,
        animation: _controllerOp,
        child: new Container(
          margin: new EdgeInsets.symmetric(vertical: 10.0),
          height: 150.0,
          width: 150.0,
          child: new FlutterLogo(),
        )
      ),
    );
  }

对于大量的代码感到抱歉,我不确定哪个部分我可以犯错误。

1 个答案:

答案 0 :(得分:2)

我认为你的方向正确,但每AnimationController只能使用一个AnimatedWidget。我修复了代码中的一些错误。

video of pulsing flutter logo

import 'package:flutter/material.dart';
import 'dart:math' as math;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new AppLoader(),
    );
  }
}

class PulsateCurve extends Curve {
  @override
  double transform(double t) {
    if (t == 0 || t == 1)
      return 0.3;
    return math.sin(t * math.PI) * 0.35 + 0.65;
  }
}

class AnimatedLoader extends AnimatedWidget {
  static final _opacityTween = new CurveTween(curve: new PulsateCurve());

  AnimatedLoader({
    Key key,
    this.alignment: FractionalOffset.center,
    Animation<double> animation,
    this.child,
  }) : super(key: key, listenable: animation);

  final FractionalOffset alignment;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    final Matrix4 transform = new Matrix4.rotationZ(animation.value * math.PI * 2.0);
    return new Transform(
        alignment: alignment,
        transform: transform,
        child: new Opacity(
          opacity: _opacityTween.evaluate(animation),
          child: child,
        )
    );
  }
}

class AppLoader extends StatefulWidget {
  AppLoaderState createState() => new AppLoaderState();
}

class AppLoaderState extends State<AppLoader> with TickerProviderStateMixin {
  AnimationController _controller;

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

  @override
  Widget build(BuildContext context) {
    return new Center (
      child: new AnimatedLoader(
          animation: _controller,
          alignment: FractionalOffset.center,
          child: new Container(
            margin: new EdgeInsets.symmetric(vertical: 10.0),
            height: 150.0,
            width: 150.0,
            child: new FlutterLogo(),
          )
      ),
    );
  }
}