Flutter动画如何逐渐淡入/淡出

5

我正在学习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(),
        )
      ),
    );
  }

非常抱歉给你带来这么长的代码块,我不确定哪部分可能出现了错误。


你可以尝试使用AnimatedOpacity而不是Opacity吗?只是一个想法 :) - Rainer Wittmann
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
3

我认为你走在正确的道路上,但是每个AnimatedWidget只应使用一个AnimationController。我已经修复了你代码中的一些错误。

闪烁的Flutter标志视频

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(),
          )
      ),
    );
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,