Base on macOS 10.15, Xcode 11.7.
1. 等效
暂且不看对外部视图的影响的话,withAnimation() 和 AnyTransition.animation() 对于其修饰的视图其实是相同效果的不同写法。
Button("show/hide"){ withAnimation { self.show.toggle() } } if show { Text("hello") .transition(.scale) }
等效于:
Button("show/hide"){ self.show.toggle() } if show { Text("hello") .transition(AnyTransition.scale.animation(.default)) }
还有一个要注意! 在那几种 AnyTransition 中,只有对 .opacity 与 .scale 直接调用 animation() 是有效的。而对于 .slide, .move, .offset 这几种,是要将 .transition() 修饰器与 .animation() 修饰器连用才行。即:
withAnimation { self.show.toggle() } if show { Text("hello").transition(.move(edge: .top)) } 等效于: if show { Text("hello") .transition(.move(edge: .top)) .animation(.default) }
呃,我也无法理解 SwiftUI 为什么会有这种幺蛾子。。 =。=#
指定 Animation 的话
Button("show/hide"){ withAnimation(Animation.easeInOut(duration: 1)) { self.show.toggle() } } if show { Text("hello") .transition(.scale) }
等效于:
Button("show/hide"){ self.show.toggle() } if show { Text("hello") .transition(AnyTransition.scale.animation(Animation.easeInOut(duration: 1))) }
2. 区别
但是在实际的使用中,如果父视图的 size 是非固定大小的,那么使用 withAnimation() 可能会导致父视图也出现连锁的“动画”异动。以上述的例子,我把完整代码与截图贴出来对比一下就知道:
2.1 使用 withAnimation 的效果
struct ContentView: View { @State var show = false var body: some View { VStack { Button("show/hide"){ withAnimation(Animation.easeInOut(duration: 1)) { self.show.toggle() } } Divider() if show { Text("hello") .transition(.scale) } }.padding() } }
可以看到动画效果影响到了 “show/hide” 按钮与分割线,这并不是我们想要的结果。
2.2 只在对应视图使用 AnyTransition. animation() 的效果
ct ContentView: View { @State var show = false var body: some View { VStack { Button("show/hide"){ self.show.toggle() } Divider() if show { Text("hello") .transition(AnyTransition.scale.animation(Animation.easeInOut(duration: 1))) } }.padding() } }
“show/hide” 按钮纹丝未动,这才是我们想要的。
3. 结论
对于要实现动画效果的视图,还是尽量只在该视图上使用 .animation() 修饰器,与 .transition(AnyTransition.animation()) 修饰器。withAnimation() 在写法上又多余,还可能携带副作用,不明白它有啥用呢😠 。
感谢总结的很实用