SwiftUI – withAnimation 和 AnyTransition. animation() 的区别

SwiftUI – withAnimation 和 AnyTransition. animation() 的区别

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() 在写法上又多余,还可能携带副作用,不明白它有啥用呢😠 。

 

发表评论

邮箱地址不会被公开。 必填项已用*标注