FadeTransition 和 AnimatedOpacity 彼此不同步

FadeTransition and AnimatedOpacity are not in sync with each other

最小可重现代码:

static const Duration _duration = Duration(seconds: 5);
static const Curve _curve = Curves.fastOutSlowIn;
AnimationController _controller;
bool _flag = false;

@override
void initState() {
  super.initState();
  _controller = AnimationController(vsync: this, duration: _duration);
}

@override
Widget build(BuildContext context) {
  final box = Container(color: Colors.orange, width: 100, height: 100);
  return Scaffold(
    body: Column(
      children: [
        FadeTransition(
          opacity: CurvedAnimation(parent: _controller, curve: _curve),
          child: box,
        ),
        SizedBox(height: 20),
        AnimatedOpacity(
          curve: _curve,
          duration: _duration,
          opacity: _flag ? 1 : 0,
          child: box,
        ),
        SizedBox(height: 20),
        RaisedButton(
          onPressed: () {
            setState(() {
              _flag = !_flag;
              if (_flag) {
                _controller.forward();
              } else {
                _controller.reverse();
              }
            });
          },
          child: Text(_flag ? 'Hide' : 'Show'),
        ),
      ],
    ),
  );
}

输出:

如您所见,两个动画彼此不同步。我对 FadeTransitionAnimatedOpacity 使用相同的 CurveDuration。但是,如果删除 curve,则动画同步。那么,我在这里做错了什么?

当您调用 _controller.reverse() 时,FadeTransition 使用反向曲线,但 AnimatedOpacity 使用相同的曲线。您可以添加 FlippedCurve 小部件来修复它。

而你不等到结束就停止动画,controller.reverse,将从停止点开始向相反的方向移动。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  static const Duration _duration = Duration(seconds: 5);
  static const Curve _curve = Curves.fastOutSlowIn;

  AnimationController _controller;
  bool isShowing = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: _duration);
  }

  @override
  Widget build(BuildContext context) {
    final box = Container(color: Colors.orange, width: 100, height: 100);
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FadeTransition(
              opacity: CurvedAnimation(parent: _controller, curve: _curve),
              child: box,
            ),
            SizedBox(height: 20),
            AnimatedOpacity(
              curve: isShowing ? _curve : FlippedCurve(_curve),
              duration: _duration,
              opacity: isShowing ? 1 : 0,
              child: box,
            ),
            SizedBox(height: 20),
            RaisedButton(
              onPressed: () {
                setState(() {
                  if (isShowing) {
                    _controller.reverse();
                  } else {
                    _controller.forward();
                  }
                  isShowing = !isShowing;
                });
              },
              child: Text(isShowing ? 'Hide' : 'Show'),
            ),
            AnimatedBuilder(
                builder: (_, __) {
                  return Text(
                    _controller.value.toString(),
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  );
                },
                animation: _controller)
          ],
        ),
      ),
    );
  }
}

我错过了 reverseCurve 参数。

FadeTransition(
  opacity: CurvedAnimation(
    parent: _controller,
    curve: _curve,
    reverseCurve: _curve, // Solved the problem. 
  ),
  child: box,
)