前言
之前的两篇文章animating paths 和 transform matrices 对 Animatable 协议使用做了介绍,今天这篇文章将为大家介绍 AnimatableModifier,使用它可以完成更多的动画工作。
AnimatableModifier 是一个 ViewModifier,符合 Animatable 协议,如果对这个协议不了解可以阅读之前发布的两篇文章。
AnimatableModifier 无法实现动画
如果是第一次使用 AnimatableModifier,可能会遇到问题。写一个简单的动画,但是没有动画效果。 我又试了几次,也没有成功。因此我认为该功能不存并且放弃使用。幸运的是,后来我坚持了下来。事实证明,我的第一个 modifier
非常好,但是 animatable modifiers
在容器中不起作用。 我在第二次尝试时,动画视图不在容器内。
例如,以下 modifier 可以成功实现动画:
1 | MyView().modifier(MyAnimatableModifier(value: flag ? 1 : 0)) |
但是相同的代码,在 VStack 中就没有动画了:
1 | VStack { |
这个问题在官方解决之前,经过尝试,可以在 VStack 中改成下面的代码,就可以实现动画:
1 | VStack { |
这样写是使用一个透明视图占据实际视图空间,动画被放在透明视图上,使用 .overlay()
。有点不方便的是,我们需要知道实际视图有多大,所以我们可以在它后面设置透明视图的框架。在下面的示例中可以开到实现代码。
动画文本
首先需要制作一些文字动画。对于这个例子,我们将创建一个进度加载指示器。
可能很多人都认为应该使用动画路径实现。但是,内部标签就无法设置动画,使用 AnimatableModifier
可以实现。
完整的代码作为 示例10 在文末链接中。关键代码如下:
1 | struct PercentageIndicator: AnimatableModifier { |
在示例代码中可以看到,没有使 ArcShape animatable
。 因为 modifier
已经多次创建形状,具有不同的 pct 值。
动画渐变
在实现渐变动画时,可能会遇到一些限制。比如,可以为起点和终点设置动画,但是不能为渐变颜色设置动画。使用 AnimatableModifier
可以避免出现这种情况。
很容易就可以实现这个功能,在这个基础上可以实现更多复杂的动画。如果需要插入中间颜色,我们只需要计算 RGB 值的平均值。另外需要注意,modifier
假设输入颜色数组都包含相同数量的颜色。
完整的代码作为 示例11 在文末链接中。关键代码如下:
1 | struct AnimatableGradient: AnimatableModifier { |
更多文本动画
这个示例中,将再次实现一个文本动画。但是是逐步进行,一次放大一个字符
完整的代码作为 示例12 在文末链接中。关键代码如下:
1 | struct WaveTextModifier: AnimatableModifier { |
计数器动画
如果你没有用过或者对 AnimatableModifier 不了解,下面这个示例基本上是无法实现的。下面我们来介绍一下如何创建一个计数器动画:
这个练习的诀窍是为每个数字使用 5 个文本视图,并使用 .spring() 动画上下移动它们。 我们还需要使用 .clipShape() 修饰符来隐藏在边框之外绘制的部分。 为了更好地理解它是如何工作的,您可以评论 .clipShape() 并大大减慢动画的速度。 完整代码在本页顶部链接的 gist 文件中以 Example13 的形式提供。
这个动画实现的主要内容是每个数字使用 5 个文本视图,并使用 .spring() 动画上下移动它们。然后使用 .clipShape()
修饰符来隐藏边框之外区域。如果想跟清晰的理解他们是如何实现的,可以通过 .clipShape()
让动画速度变慢。
完整的代码作为 示例13 在文末链接中。关键代码如下:
1 | struct MovingCounterModifier: AnimatableModifier { |
动画文本颜色
通常情况下是通过 .foregroundColor()
为动画添加颜色,但是在文本类动画中使用没有效果,不知道是缺少什么配置还是什么原因。我通过下面的方法实现给文本动画添加颜色。
完整的代码作为 示例14 在文末链接中。关键代码如下:
1 | struct AnimatableColorText: View { |
版本相关问题
通过上面介绍可以看出 AnimatableModifier
非常强大,但是还存在一些问题。另外在 Xcode 和 iOS/macOS 某些版本中,App 在启动时会崩溃。而且是在部署时,正常开发编译中是不会发生这种情况。
1 | dyld: Symbol not found: _$s7SwiftUI18AnimatableModifierPAAE13_makeViewList8modifier6inputs4bodyAA01_fG7OutputsVAA11_GraphValueVyxG_AA01_fG6InputsVAiA01_L0V_ANtctFZ |
例如,如果 App 在 Xcode 11.3 上部署并在 macOS 10.15.0 上执行,就会出现 “Symbol not found” 错误。然而,在 macOS 10.15.1 上运行相同的可执行文件可以正常工作。
译自 The SwiftUI Lab 的 Advanced SwiftUI Animations – Part 3: AnimatableModifier
本文的完整示例代码可在以下位置找到:
https://gist.github.com/swiftui-lab/e5901123101ffad6d39020cc7a810798
示例8 需要的图片资源。从这里下载:
https://swiftui-lab.com/?smd_process_download=1&download_id=916