Flutter Animate

一个库,可以轻松地在 Flutter 中添加几乎任何类型的动画效果。

  1. 预置效果,如模糊、淡入淡出、缩放和滑动
  2. 简单的自定义效果
  3. 简化的动画构建器
  4. 同步事件

所有这些都通过一个简单、统一的 API 实现,无需处理 AnimationController 和 StatefulWidget。

注意:该库目前处于预发布阶段。随着其完善,API 的某些方面将会发生变化。欢迎通过 Github issue 提供您的反馈。

持续时间扩展

此包包含 `num` 的扩展方法,可更轻松地指定持续时间。例如:`2.seconds`、`0.1.minutes` 或 `300.ms`。

基础

语法

要应用效果,请将目标小部件包装在 `Animate` 中,并指定效果列表

Animate(
  effects: [FadeEffect(), ScaleEffect()],
  child: Text("Hello World!"),
)

它还为所有小部件添加了一个 `.animate()` 扩展方法,该方法将小部件包装在 `Animate()` 中。每种效果还为 `Animate` 添加了一个可链式调用的扩展方法,以启用简短语法

Text("Hello World!").animate().fade().scale()

注意:此 README 中使用了简短风格,但所有功能都可通过任一格式使用。

延迟、持续时间和曲线

效果具有可选的 `delay`、`duration` 和 `curve` 参数。效果并行运行,但您可以使用 `delay` 来顺序运行它们

Text("Hello").animate()
  .fade(duration: 500.ms)
  .scale(delay: 500.ms) // runs after fade.

请注意,效果在整个动画的持续时间内都是“活跃”的,因此,例如,对同一目标的两个淡入淡出效果可能会产生意想不到的结果(下面详述的 `SwapEffect` 可以帮助解决此问题)。

如果未指定(或为 null),这些值将从上一个效果继承,或者从 `Animate.defaultDuration` 和 `Animate.defaultCurve` 继承(如果这是第一个效果)。

Text("Hello World!").animate()
  .fadeIn() // uses `Animate.defaultDuration`
  .scale() // inherits duration from fadeIn
  .move(delay: 300.ms, duration: 600.ms) // runs after the above w/new duration
  .blur(end: 8.0) // inherits the delay & duration from move

动画列表

`AnimateList` 类为小部件列表提供了类似的功能,可以选择通过指定的 `interval` 来偏移每个子项的动画。

Column(children: AnimateList(
  interval: 400.ms,
  effects: [FadeEffect(duration: 300.ms)],
  children: [Text("Hello"), Text("World"),  Text("Goodbye")],
))

// or shorthand:
Column(
  children: [Text("Hello"), Text("World"),  Text("Goodbye")]
    .animate(interval: 400.ms).fade(duration: 300.ms),
)

自定义效果和构建器

通过扩展 `Effect` 可以轻松编写新的可重用效果,但您也可以通过使用 `CustomEffect`、`ToggleEffect` 和 `SwapEffect` 来轻松创建一次性的自定义效果。

CustomEffect

`CustomEffect` 允许您构建自定义动画效果。只需指定一个接受 `context`、`value` 和 `child` 的 `builder` 函数。child 是动画的目标(可能已被包装在其他效果中)。

例如,这将为文本添加一个背景,并将其从红色淡入蓝色

Text("Hello World").animate().custom(
  duration: 300.ms,
  builder: (context, value, child) => Container(
    color: Color.lerp(Colors.red, Colors.blue, value),
    padding: EdgeInsets.all(8),
    child: child, // child is the Text widget being animated
  )
)

默认情况下,`value` 提供一个从 `0-1` 的值(尽管某些曲线可以生成超出此范围的值),该值基于当前时间、持续时间和曲线。您也可以指定 `begin` 和 `end` 值,如下面的示例所示。

`Animate` 可以在没有 child 的情况下创建,因此您可以使用 `CustomEffect` 作为简化的构建器。例如,这将显示从 10 开始倒计时并淡出的文本。

Animate().custom(
  duration: 10.seconds,
  begin: 10,
  end: 0,
  builder: (_, value, __) => Text(value.round()),
).fadeOut()

ToggleEffect

`ToggleEffect` 也提供了 builder 功能,但它提供一个布尔值,而不是 `double`。该布尔值在效果结束前(即其持续时间之后)为 `true`,在效果结束后为 `false`。

Animate().toggle(
  duration: 2.seconds,
  builder: (_, value, __) => Text(value ? "Before" : "After"),
)

这也可以用于激活“动画”小部件,例如 `AnimatedContainer`,通过在最小延迟的情况下切换它们的值。

Animate().toggle(
  duration: 1.ms,
  builder: (_, value, __) => AnimatedContainer(
    duration: 1.second,
    color: value ? Colors.red : Colors.green,
  ),
)

SwapEffect

`SwapEffect` 允许您在指定时间交换目标小部件。

Text("Before").animate().swap(duration: 900.ms, builder: (_) => Text("After"))

这也有助于创建顺序效果,通过将目标小部件重新换回,从而有效地消除所有先前的影响。

Widget text = Text("Hello World!");

// then:
text.animate().fadeOut(300.ms) // fade out & then...
  .swap(builder: (_) => text.fadeIn()) // swap in original widget & fade back in

事件和回调

`Animate` 上有 `onInit` 和 `onComplete` 回调,在整个动画开始或结束时触发。使用提供的 `AnimationController` 来操作动画(例如,重复、反转等)。

Text("Pulsing Text")
  .animate(onComplete: (controller) => controller.repeat(reverse: true))
  .fadeOut(delay: 300.ms, duration: 300.ms, curve: Curves.easeIn)

有关更细致的回调,请使用 `CallbackEffect` 或 `ListenEffect`。

CallbackEffect

`CallbackEffect` 允许您在动画的任意位置添加回调。例如,在淡入淡出过程中添加一个回调。

Text("Hello").animate().fadeIn(duration: 600.ms)
  .callback(duration: 300.ms, callback: () => print('halfway'))

与其他效果一样,它将继承先前效果的延迟和持续时间。

Text("Hello").animate().scale(delay: 200.ms, duration: 400.ms)
  .callback(callback: () => print('scale is done'))

ListenEffect

`ListenEffect` 允许您注册一个回调,以接收给定延迟、持续时间和曲线的动画值(作为 `double`)。

Text("Hello").animate().fadeIn(curve: Curves.easeOutExpo)
  .listen(callback: (value) => print('current opacity: $value'))

上面的示例有效,因为监听效果从淡入效果继承了持续时间和曲线,并且两者默认都使用 `begin=0, end=1`。

GitHub

查看 Github