Flutter何时应该使用animatedbuilder或AnimatedWidget?

262 阅读5分钟

我们知道你在飞行时有很多选择,我是说动画,在Flutter中,所以感谢你选择了AnimatedBuilder和AnimatedWidget。等等,什么?不!Flutter有许多不同的动画小部件,但与商业航空公司不同,每种类型的小部件适合不同类型的工作。当然,你可以用几种不同的方法来完成同样的动画,但是使用正确的动画小部件会让你的生活更轻松。

本文介绍了为什么要使用AnimatedBuilder或AnimatedWidget而不是其他动画小部件,以及如何使用它们。假设您要向应用程序添加动画。本文是本系列文章的一部分,详细介绍了为什么要使用每种类型的动画小部件。

你想要做的特定动画会重复几次,或者需要能够暂停和恢复以响应某些东西,比如手指轻触。因为动画需要重复,或者停止和开始,所以需要使用显式动画。

作为提醒,在Flutter中我们有两大类动画:显式和隐式。对于显式动画,需要一个动画控制器。对于隐式动画,则不需要。我们在上一篇关于内置显式动画的文章中介绍了动画控制器。如果你想了解更多,请先看看。

因此,如果您确定需要显式动画,那么有一整套显式动画类供您选择。这些类通常命名为footTransition,其中Foo是您尝试动画化的属性的名称。

我建议您在深入了解AnimatedWidget和AnimatedBuilder之前,先看看是否可以使用其中一个小部件来满足您的需求。有一个惊人的小部件选择几乎任何你能想到的-旋转,位置,对齐,褪色,文本样式,等等。另外,你可以组合这些小部件,这样你就可以旋转和淡出。但是,如果这些内置的小部件都不能满足您的需要,那么就应该使用AnimatedWidget或AnimatedBuilder来构建自己的widget了。

具体实例  

为了让这更具体,让我们来看看一个具体的场景:我想用一个外星飞船编写一个应用程序,并制作一个飞船光束动画。

我画了一个太空船光束,渐变从黄色渐变为透明,从渐变的中心开始渐变。然后,我用路径裁剪器从渐变创建了“光束”形状。 我想创建一个“光束向下”的动画,从渐变的中心开始,我想让它重复。这意味着我需要创建一个明确的动画。不幸的是,没有内置的显式动画来设置漏斗形渐变的动画,但是你知道我们有什么…AnimatedWidget和AnimatedBuilder来完成这个技巧!

AnimatedBuilder

为了使光束动起来,我将把这个渐变代码包装在AnimatedBuilder小部件中。渐变代码放在builder函数中,在AnimatedBuilder生成时调用该函数。 接下来我需要添加一个控制器来驱动这个动画。控制器提供AnimatedBuilder用于逐帧绘制动画新版本的值。正如您在上一篇文章中看到的,我混合了SingleTickerProviderStateMixin类,并在initState函数中实例化控制器,这样它只创建一次。我在initState中创建控制器,而不是build方法,因为我不想多次创建这个控制器-我希望它为每个帧提供新的动画值!因为我在initState中创建了一个新对象,所以我添加了一个dispose方法并告诉Flutter,当父窗口小部件不再出现在屏幕上时,它可以去掉该控制器。 然后,我将该控制器传递给AnimatedBuilder,然后我的动画按预期运行!

 您可能还记得在TweenAnimationBuilder文章中,我们使用子参数作为性能优化,我们也可以使用AnimatedBuilder来实现这一点。基本上,如果我们有一个在动画过程中从未改变过的对象,我们可以提前构建它,并将其传递给AnimatedBuilder。 在这种特定的情况下,完成相同任务的更好方法是给BeamClipper一个const构造函数,并使其成为const。它的代码更少,而且对象是在编译时创建的,这使得速度更快。但是,有时您将编写没有const构造函数的代码,这是一个很好的例子,说明何时使用这个可选的子参数。

AnimatedWidget

所以,我们有了动画,但是包含AnimatedBuilder代码的build方法有点大。如果你的构建方法开始变得难以阅读,那么是时候重构你的代码了! 您可以将AnimatedBuilder代码拖出到一个单独的小部件中,但是在构建方法中只有一个build方法,这有点傻。相反,您可以通过创建一个扩展AnimatedWidget的新小部件来完成相同的动画。我将把我的widget命名为BeamTransition,以符合显式动画的foottransition命名约定。我将动画控制器传递给BeamTransition,并重用AnimatedBuilder的builder函数体。 就像AnimatedBuilder一样,如果合适的话,我可以将一个子参数添加到我的小部件中作为性能优化,这样它就可以提前构建,而不是每次我设置动画。不过提醒一下,在这个例子中,让我的BeamClipper使用const构造函数是最好的方法。

那么说真的,我该用哪一个呢?

 我们刚刚看到了AnimatedBuilder和AnimatedWidget如何在找不到一个内置的显式动画来执行您想要的动画时,如何使用AnimatedBuilder和AnimatedWidget来完成相同类型的显式动画。那么,你应该用哪一个呢?这真的是一个品味的问题。一般来说,我建议制作单独的小部件,每个小部件都有一个单独的任务——在本例中是动画。 这是一个投票赞成尽可能使用AnimatedWidget。但是,如果创建动画控制器的父控件非常简单,那么只为动画制作单独的小部件可能会有太多额外的代码。在这种情况下,AnimatedBuilder就是您所需要的。