首页 > 解决方案 > 调用 SetState() 后 SlideAnimation 不再启动

问题描述

我制作了一个简单的类,用于将小部件动画化到屏幕中:

class CustomSlideAnimation extends StatefulWidget {
  static const String FROM_LEFT = 'FROM_LEFT';
  static const String FROM_RIGHT = 'FROM_RIGHT';
  final String from;
  final Widget child;

  const CustomSlideAnimation(
      {Key key, this.from = FROM_LEFT, @required this.child})
      : super(key: key);

  @override
  _CustomSlideAnimationState createState() => _CustomSlideAnimationState();
}

class _CustomSlideAnimationState extends State<CustomSlideAnimation>
    with SingleTickerProviderStateMixin {
  Animation<Offset> _offsetAnimation;
  AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));
    _offsetAnimation = widget.from == CustomSlideAnimation.FROM_LEFT
        ? Tween<Offset>(
            begin: Offset(-1.0, 0.0),
            end: Offset.zero,
          ).animate(CurvedAnimation(
            curve: Curves.linear,
            parent: _animationController,
          ))
        : Tween<Offset>(
            begin: Offset(1.0, 0.0),
            end: Offset.zero,
          ).animate(CurvedAnimation(
            curve: Curves.linear,
            parent: _animationController,
          ));
    _animationController.forward();
  }

  @override
  void dispose() {
    super.dispose();
    _animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _offsetAnimation,
      child: widget.child,
    );
  }
}

还有一个简单的应用程序来演示这个问题:

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

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  bool widget1 = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: widget1
              ? CustomSlideAnimation(
                  child: InkWell(
                    child: Text('widget1'),
                    onTap: () {
                      setState(() {
                        widget1 = false;
                      });
                    },
                  ),
                  from: CustomSlideAnimation.FROM_LEFT,
                )
              : CustomSlideAnimation(
                  child: InkWell(
                    child: Text('widget2'),
                    onTap: () {
                      setState(() {
                        widget1 = true;
                      });
                    },
                  ),
                  from: CustomSlideAnimation.FROM_LEFT,
                ),
        ),
      ),
    );
  }
}

当我第一次启动应用程序时,Text小部件按预期滑入屏幕,但随后我点击它并调用 setState(),第二个Text小部件突然出现在屏幕上,并且没有发生幻灯片转换。

我打印了在所有类中调用 build 的时间,我看到 setState() 正在触发TestCustomSlideTransition类中的构建,但没有触发CustomSlideTransition中的initState ()

编辑以获得更多说明:即使将方法放入controller.forward()build()方法也不起作用。

那么我错过了什么?

标签: flutterdart

解决方案


你只需要给UniqueKey()每个添加一个CustomSlideAnimation()来告诉颤振把它们当作不同的小部件来对待。

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

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  bool widget1 = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: widget1
              ? CustomSlideAnimation(
                  key: UniqueKey(),
                  child: InkWell(
                    child: Text('widget1'),
                    onTap: () {
                      setState(() {
                        widget1 = false;
                      });
                    },
                  ),
                  from: CustomSlideAnimation.FROM_LEFT,
                )
              : CustomSlideAnimation(
                  key: UniqueKey(),
                  child: InkWell(
                    child: Text('widget2'),
                    onTap: () {
                      setState(() {
                        widget1 = true;
                      });
                    },
                  ),
                  from: CustomSlideAnimation.FROM_LEFT,
                ),
        ),
      ),
    );
  }
}

另外,保持controller.forward()在里面initState()


推荐阅读