SwiftUI 中的 @Namespace
和命名空间动画
#
@Namespace
是 SwiftUI 中的一个属性包装器,用于创建动画命名空间,主要用于在不同视图之间创建平滑的过渡动画,特别是匹配几何效果(Matched Geometry Effects)。
@Namespace
基本概念
#
- 作用:创建一个唯一的命名空间,用于标识视图层次结构中的特定视图
- 用途:主要用于视图间的动画过渡,特别是当两个视图在视觉上代表同一个元素但在不同位置时
- 特点:
- 命名空间在声明它的视图及其子视图中可用
- 通常与
matchedGeometryEffect
修饰符一起使用
基本用法 #
声明命名空间 #
@Namespace private var namespace
简单示例 #
struct ContentView: View {
@Namespace private var namespace
@State private var isFlipped = false
var body: some View {
VStack {
if isFlipped {
Circle()
.fill(Color.red)
.frame(width: 100, height: 100)
.matchedGeometryEffect(id: "shape", in: namespace)
} else {
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
.matchedGeometryEffect(id: "shape", in: namespace)
}
Button("切换") {
withAnimation {
isFlipped.toggle()
}
}
}
}
}
你的 bottomID
示例
#
在你的代码中:
@Namespace private var bottomID
这表示你创建了一个名为 bottomID
的命名空间,可能用于标识底部某个视图元素,以便在视图变化时创建平滑的动画过渡。
实际应用场景 #
1. 列表到详情过渡 #
struct ListView: View {
@Namespace private var namespace
@State private var selectedItem: Item?
var body: some View {
if let item = selectedItem {
DetailView(item: item, namespace: namespace)
} else {
ScrollView {
ForEach(items) { item in
ItemView(item: item)
.matchedGeometryEffect(id: item.id, in: namespace)
.onTapGesture {
withAnimation {
selectedItem = item
}
}
}
}
}
}
}
2. TabView 切换动画 #
struct TabViewExample: View {
@Namespace private var namespace
@State private var selectedTab = 1
var body: some View {
HStack {
ForEach(1...3, id: \.self) { tab in
Text("Tab \(tab)")
.padding()
.background(
if selectedTab == tab {
Color.blue
.matchedGeometryEffect(id: "tab", in: namespace)
}
)
.onTapGesture {
withAnimation {
selectedTab = tab
}
}
}
}
}
}
使用注意事项 #
- 唯一标识:确保
id
在同一命名空间中是唯一的 - 视图层级:命名空间只在声明它的视图及其子视图中可用
- 性能考虑:避免在大型列表中使用过多匹配几何效果
- 动画控制:通常与
withAnimation
一起使用以获得平滑过渡
高级用法 - 复杂过渡 #
struct AdvancedExample: View {
@Namespace private var namespace
@State private var showDetail = false
var body: some View {
ZStack {
if !showDetail {
VStack {
Text("标题")
.matchedGeometryEffect(id: "title", in: namespace)
Image(systemName: "photo")
.matchedGeometryEffect(id: "image", in: namespace)
Button("查看详情") {
withAnimation(.spring()) {
showDetail = true
}
}
.matchedGeometryEffect(id: "button", in: namespace)
}
} else {
DetailView(namespace: namespace) {
withAnimation(.spring()) {
showDetail = false
}
}
}
}
}
}
@Namespace
是 SwiftUI 中创建精美视图过渡的强大工具,合理使用可以显著提升应用的用户体验。