Flutter:如何用 Provider 播放动画?

Posted

技术标签:

【中文标题】Flutter:如何用 Provider 播放动画?【英文标题】:Flutter: how to play animation with Provider? 【发布时间】:2020-02-28 21:04:46 【问题描述】:

我在 Flutter 演示中使用 Provider 来管理状态。

我想为我的小部件设置动画,但似乎 AnimateController 需要一个来自有状态小部件状态的同步参数。

据我所知,不建议将 Provider 与有状态小部件一起使用。

我可以用Provider管理AnimationController吗?

或者必须同时使用 Provider 和 stateful widget?

【问题讨论】:

动画属于 UI,而不是状态。您需要为动画控制器提供一个 Ticker。您可以使用 SingleTickerProviderStateMixin 来避免手动创建它。 api.flutter.dev/flutter/widgets/… @RicardoMarkiewicz 如果我想从同一个父母的不同孩子触发动画怎么办 @RicardoMarkiewicz 但我们都同意状态定义 UI?我认为 Javan 想知道当小部件树被破坏时如何在状态变化时制作漂亮的动画。 Provider 很容易处理,但是状态变化时小部件的即时切换很奇怪。你如何解决这个问题?假设你推送登录,应用程序开始登录,然后切换到下载配置文件,下载这个和那个,最后看到最终的登录界面? 您的动画控制器应该在 UI 部分,而不是在状态类中,因为动画不是您的应用程序状态的一部分(例如,您的用户是否已登录?)而是 UI 瞬态状态的一部分(状态当您离开该屏幕时会迷路)。你需要使用 boh Provider 和 StatefulWidget,你可以使用 AnimatedWidget,你可以使用 FlutterHooks,但永远不要从你的状态/模式类管理你的动画。 【参考方案1】:

我可以用Provider管理AnimationController吗?

或者必须同时使用 Provider 和 stateful widget?

我不知道这是否是最好的方法,但我是这样做的:

我在有状态小部件中使用didUpdateWidget。我将值从提供者传递给父级,并在子级中定义的didUpdateWidget 方法中触发动画。 didUpdateWidget 当我通知听众提供者发生变化时自动触发。

class MyWidget extends StatefulWidget 
  final String valueFromProvider;

  MyWidget(this.valueFromProvider);

  @override
  _MyWidgetState createState() => _MyWidgetState();


class _MyWidgetState extends State<MyWidget> with TickerProviderStateMixin 
  @override
  void didUpdateWidget(MyWidget oldWidget) 
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);

    if (oldWidget.valueFromProvider == "whatever you want" &&
        widget.valueFromProvider == "what you want that changed") 
      // trigger animations methods here
    
  

  // here all the animations methods,dispose method, etc. 

  @override
  Widget build(BuildContext context) 
    return Container();
  

【讨论】:

【参考方案2】:

如果你想在 StatelessWidget 中创建 AnimationController,你必须在 StatelessWidget 的构造函数中传递 TickerProviderStateMixin,看看我的示例代码:

import 'package:flutter/material.dart';

main() 
  runApp(TestyApp());


class TestyApp extends StatefulWidget 
  @override
  _TestyAppState createState() => _TestyAppState();


class _TestyAppState extends State<TestyApp> with TickerProviderStateMixin 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: TestAnimationInStatelessWidget(
        tickerProviderStateMixin: this,
      ),
    );
  


class TestAnimationInStatelessWidget extends StatelessWidget 
  final TickerProviderStateMixin tickerProviderStateMixin;

  const TestAnimationInStatelessWidget(
      Key key, @required this.tickerProviderStateMixin)
      : assert(tickerProviderStateMixin != null),
        super(key: key);

  @override
  Widget build(BuildContext context) 

    var _animationController = AnimationController(
        vsync: tickerProviderStateMixin, duration: Duration(seconds: 1));

    var _animation = Tween<double>(begin: 0, end: 2).animate(CurvedAnimation(
        parent: _animationController, curve: Curves.easeInOut));

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            RotationTransition(
              turns: _animation,
              child: Container(
                width: 200,
                height: 200,
                decoration: BoxDecoration(
                  color: Colors.blueGrey,
                  borderRadius: BorderRadius.all(Radius.circular(15)),
                ),
              ),
            ),
            SizedBox(
              height: 30,
            ),
            RaisedButton(
              onPressed: () 
                _animationController.reset();
                _animationController.forward();
              ,
              child: Text("Start Animation"),
            )
          ],
        ),
      ),
    );
  

【讨论】:

在您的示例中,您使用的是有状态小部件。【参考方案3】:

我做了一个解决方法,覆盖了 didChangeDependencies 方法,该方法会在出现提示时触发 AnimationController.forward。

我从这个 *** 线程 link 得到这个想法

@override
  void didChangeDependencies() 
    super.didChangeDependencies();

    var result = Provider.of<Home>(context).notification;
    if (result == "Play") 
      _controller.forward();
    
  

但是,这只是一种解决方法,我仍在寻找一种更有效的方法来管理它(使用 Provider / 或其他解决方案,在另一个不相关的小部件中的有状态小部件中启动/停止动画)。

【讨论】:

以上是关于Flutter:如何用 Provider 播放动画?的主要内容,如果未能解决你的问题,请参考以下文章

unity3d 如何用GUI按钮播放动画脚本怎么写

在 Flutter 中使用 Provider 更新和动画化 AnimatedList

如何为 Flutter SliverList 中的元素设置动画?

如何用JavaScript捕获CSS3的动画事件

Flutter - 我的动画只播放一次

Flutter Provider:为啥在调用 Provider.of<Widget>(context) 时会出现此错误,如 tihis: