@Namespace 是 SwiftUI 中的一个属性包装器,用于创建动画的共享命名空间。它主要应用于 SwiftUI 的匹配几何效果(MatchedGeometryEffect),以在两个视图之间实现平滑的过渡动画。
基本概念
@Namespace 创建一个标识符,供视图间共享。使用该标识符时,SwiftUI 能够将视图的几何信息(如位置、大小)关联起来,从而计算出它们之间的动画路径。
使用场景
1、视图过渡动画
在两个视图之间进行元素的平滑过渡。
2、重用同一个视图的几何信息
动态调整视图的布局和动画。
基本语法
@Namespace private var animationNamespace
1、声明一个 @Namespace 属性。
2、使用 .matchedGeometryEffect(id:namespace:) 修饰视图,并为其指定唯一的 ID 和命名空间。
示例
视图间的平滑过渡
struct MatchedGeometryExample: View {
@Namespace private var namespace
@State private var isExpanded = false
var body: some View {
VStack {
if isExpanded {
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.matchedGeometryEffect(id: "shape", in: namespace)
.frame(width: 300, height: 300)
.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
} else {
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.matchedGeometryEffect(id: "shape", in: namespace)
.frame(width: 100, height: 100)
.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
}
}
}
}
解析:
@Namespace:用于创建动画共享空间。
matchedGeometryEffect:将两个视图连接到同一个动画空间,通过相同的 id 和 namespace 实现过渡效果。
withAnimation:触发动画,SwiftUI 自动计算动画路径。
运行效果:点击小矩形时,视图平滑过渡到大矩形的位置和尺寸。
动态列表中的动画
@Namespace 在动态内容(如列表或网格)中也非常有用,用于在视图的插入、删除、移动之间实现动画。
struct DynamicListExample: View {
@Namespace private var namespace
@State private var items = ["Apple", "Banana", "Cherry", "Date"]
var body: some View {
VStack {
ForEach(items, id: \.self) { item in
Text(item)
.font(.headline)
.padding()
.background(Color.yellow)
.cornerRadius(10)
.matchedGeometryEffect(id: item, in: namespace)
}
Button("Delete Item") {
withAnimation {
if !items.isEmpty {
items.remove(at: items.count - 1)
}
}
}
Button("Add Item") {
withAnimation {
items.append("New Item \(items.count + 1)")
}
}
}
}
}
运行效果:当添加或删除元素时,视图的位置和内容会通过平滑动画更新。
关键点总结
1、声明命名空间
使用 @Namespace 创建命名空间,确保动画的关联性。
2、使用 matchedGeometryEffect
通过设置相同的 id 和 namespace,SwiftUI 知道哪些视图应该共享动画。
3、支持动态布局
动态列表或复杂布局中,@Namespace 能显著提升动画效果。
高级用法
多个元素同步动画
@Namespace 可以为多个元素同步动画,例如一个列表项的图片和文本。
struct MultipleElementsExample: View {
@Namespace private var namespace
@State private var isExpanded = false
var body: some View {
VStack {
if isExpanded {
VStack {
Image(systemName: "star.fill")
.font(.largeTitle)
.foregroundColor(.yellow)
.matchedGeometryEffect(id: "icon", in: namespace)
Text("Favorite Item")
.font(.headline)
.matchedGeometryEffect(id: "text", in: namespace)
}
.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
} else {
HStack {
Image(systemName: "star.fill")
.font(.title)
.foregroundColor(.yellow)
.matchedGeometryEffect(id: "icon", in: namespace)
Text("Favorite Item")
.font(.subheadline)
.matchedGeometryEffect(id: "text", in: namespace)
}
.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
}
}
}
}
运行效果:点击视图时,图片和文本同步过渡到新位置。
@Namespace 是 SwiftUI 中非常强大的工具,特别适合用来实现平滑过渡动画,提升界面交互效果。通过正确管理动画的命名空间和几何效果,可以显著优化用户体验。