在 SwiftUI 中为什么应该尽量避免直接使用 animation(_:) 方法创建动画?
Posted 大熊猫侯佩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在 SwiftUI 中为什么应该尽量避免直接使用 animation(_:) 方法创建动画?相关的知识,希望对你有一定的参考价值。
概览
在 SwiftUI 开发中,视图动画的点缀可以让界面更加鲜活灵动。
不过,如果在视图上错误的应用动画可能会适得其反,不但让用户使用时一头雾水,也让开发者在调试时“怒发冲冠”。
如上图所示:在用户关闭 sheet 弹出视图最后返回主界面时,会发现原本应该消失不见的蓝色光圈却向屏幕左上角反复“跳动”。
这是因为你直接在视图上应用隐式动画所导致的:
那么,到底为什么会发生这种情况呢?
Let’s find out!!! 😎
从 SwiftUI 动画的类型谈起
SwiftUI 中视图动画分为两种:隐式和显式动画。
下面,我们使用 animation(_: ) 修改器方法为视图 BigView 设置了隐式动画:
BigView(...)
.animation(.spring())
而显式动画是把引发动画状态改变的代码放在 withAnimation 方法闭包中:
BigView(...)
.scaleEffect(isImportant ? 1.5 : 1.0)
.onTapGesture
withAnimation
isImportant.toggle()
为什么博文开头例子中的动画会出现那样的问题呢?
答案就是:它使用隐式动画而不是显式动画!
隐式动画貌似简单便捷,实际会有很多不良副作用。当多个动画状态互相交织或者多个视图动画状态之间互相影响时,使用隐式动画会导致动画边界混乱化。
还拿博文开头的例子来说吧:
Circle()
.stroke(hlColor, lineWidth: 3.0)
.background(Circle().fill(hlColor.opacity(0.5)).brightness(0.5))
.frame(width: rect.width, height: rect.height)
.scaleEffect(startAnim ? 2.0 : 1.0)
.opacity(startAnim ? 0.0 : 1.0)
.animation(
Animation.easeOut(duration: 1.0)
.repeatForever(autoreverses: false)
)
如上代码所示,蓝色光圈 Circle 视图的动画实际被多个状态所影响,其中就包括 rect 和 startAnim 两个状态。
我们在 Circle 视图上应用了隐式动画,这会导致所有状态都会产生动画效果,但我们并不希望 rect 状态引发动画,因为这会导致开头蓝色光圈向屏幕左上角反复“跳动”的问题。
所以,更好的解决方案是:只响应 startAnim 状态引发的动画,使用显式动画,这很好解决。
首先,删除 Circle 视图最后的隐式动画,接着为 startAnim 状态添加显式动画:
// 需要更新 startAnim 状态时应用显式动画:
withAnimation(.easeOut(duration: 1.0).repeatForever(autoreverses: false))
startAnim.toggle()
更精确的动画方式
其实,SwiftUI 早就已经为我们考虑到了这个问题,animation 方法有另一个更为“精确”的重写方法 animation(_:value:)。
我们可以这样使用它来解决上面的问题:
Circle()
.stroke(hlColor, lineWidth: 3.0)
.background(Circle().fill(hlColor.opacity(0.5)).brightness(0.5))
.frame(width: rect.width, height: rect.height)
.scaleEffect(startAnim ? 2.0 : 1.0)
.opacity(startAnim ? 0.0 : 1.0)
// 明确告知系统只有 startAnim 状态会引发动画
.animation(.easeOut(duration: 1.0)
.repeatForever(autoreverses: false), value: startAnim)
如上所示:我们在 Circle 视图上明确告知系统,只有 startAnim 状态会引发动画效果,而其他的状态统统无视。
看一下修复后的动画效果:
现在,利用显式动画和更为精确的 animation(_:value:) 修改器方法,我们可以为任意视图更精确的实施“外科手术”般的动画效果,避免额外状态改变时的干扰,棒棒哒!💯
总结
在本篇博文中,我们讨论了 SwiftUI 中直接在视图上应用 animation(_: ) 方法创建动画的弊端,同时提出了更好、更精准的动画实现。
感谢观赏,再会!😎
以上是关于在 SwiftUI 中为什么应该尽量避免直接使用 animation(_:) 方法创建动画?的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI 中为什么应该尽量避免直接使用 animation(_:) 方法创建动画?
Unity脚本类为啥要尽量避免继承MonoBehaviour类
Java中的异常捕捉try为什么要尽量使用具体标准的异常,为什么不要直接使用ExceptionRuntimeExceptionErrorThrowable,避免在try catch中进行业务编码
Java中的异常捕捉try为什么要尽量使用具体标准的异常,为什么不要直接使用ExceptionRuntimeExceptionErrorThrowable,避免在try catch中进行业务编码