问题分析
在学习Swift UI transition时,想要通过切换transition的值来显示各种动画的差异,因此设置了Picker选择器:
Picker("显示样式", selection: $selectedTransition) {
ForEach(transitions, id: \.self) { transition in
Text(transition)
}
}
.pickerStyle(SegmentedPickerStyle())
在选择对应选项后,通过按钮来展示transition。
Form {
if isShowingRed {
Rectangle()
.fill(.red)
.frame(width: 200, height: 200)
.transition(getTransition()) // 在视图插入或移除时生效
}
}
但实际在展示中发现,无论如何点击按钮,图像显示的效果都是一样的。
经排查发现,问题在于Form具有特殊的布局行为,其布局和显示行为可能会限制某些动画效果,特别是涉及视图的插入和移除动画时,Form可能会干扰transition。
解决方案
这里可以采取两种方案:
一是在Form中添加VStack视图
Form {
VStack {
if isShowingRed {
Rectangle()
.fill(.red)
.frame(width: 200, height: 200)
.transition(getTransition()) // 在视图插入或移除时生效
}
}
}
二是移除Form:
if isShowingRed {
Rectangle()
.fill(.red)
.frame(width: 200, height: 200)
.transition(getTransition()) // 在视图插入或移除时生效
}
以下为本次案例的完整代码:
import SwiftUI
struct ContentView: View {
@State private var isShowingRed = false
@State private var selectedTransition = "scale"
@State private var transitions = ["scale", "opacity", "slide", "move", "offset"]
var body: some View {
VStack {
Form {
Button("Tap Me") {
withAnimation {
isShowingRed.toggle()
}
}
}
Form {
Picker("显示样式", selection: $selectedTransition) {
ForEach(transitions, id: \.self) { transition in
Text(transition)
}
}
.pickerStyle(SegmentedPickerStyle())
}
Form {
VStack {
if isShowingRed {
Rectangle()
.fill(.red)
.frame(width: 200, height: 200)
.transition(getTransition()) // 在视图插入或移除时生效
}
}
}
}
}
func getTransition() -> AnyTransition {
switch selectedTransition {
case "scale":
return .scale
case "opacity":
return .opacity
case "slide":
return .slide
case "move":
return .move(edge: .leading)
case "offset":
return .offset(x: 100, y: 0)
default:
return .scale
}
}
}
#Preview {
ContentView()
}