2025-01-14 10:22:08
,某些文章具有时效性,若有错误或已失效,请在下方留言。如果你在视图层次结构的两个不同部分中有相同的视图,并且希望在这两者之间进行动画过渡——例如,从列表视图切换到放大的详细视图——那么你应该使用 SwiftUI 的 matchedGeometryEffect()
修饰符,这有点像 Keynote
中的 Magic Move
。
要使用修饰符,将其附加到层次结构中不同部分的两个相同视图上。完成后,当您在两个视图状态之间切换时,会发现SwiftUI平滑地动画您的同步视图。
要尝试它,首先创建一个布局,使你的视图出现在两个位置。在这个例子中,我有一个红色的圆,然后是一些文本在一个视图状态中,但在另一个视图状态中,圆圈出现在文本之后并且颜色发生变化:
struct ContentView: View {
@State private var isFlipped = false
var body: some View {
VStack {
if isFlipped {
Circle()
.fill(.red)
.frame(width: 44, height: 44)
Text("Taylor Swift - 1989")
.font(.headline)
} else {
Text("Taylor Swift - 1989")
.font(.headline)
Circle()
.fill(.blue)
.frame(width: 44, height: 44)
}
}
.onTapGesture {
withAnimation {
isFlipped.toggle()
}
}
}
}
如果你运行那段代码,你会看到 SwiftUI 会通过淡入和淡出视图来创建一个过渡效果——这没问题,但我们可以让它更好。
![图片[1]-如何使用 matchedGeometryEffect() 将一个视图的动画同步到另一个视图-Stewed Noodles 资源](https://img.stewednoodles.com/images/2025/01/14/StewedNoodles20250114095456.gif)
首先,你需要使用@Namespace
属性包装器为你的视图创建一个全局命名空间。实际上,这只不过是视图上的一个属性,但在幕后,这使得我们可以将视图连接在一起。
所以,你可能会添加一个类似的属性:@Namespace private var animation
。
接下来,你需要将.matchedGeometryEffect(id: YourIdentifierHere, in: animation)
添加到所有你想用同步效果进行动画处理的视图中。YourIdentifierHere
部分应替换为每个配对部分共享的唯一编号。
在我们的示例中,我们可以将其用于圆圈:
.matchedGeometryEffect(id: "Shape", in: animation)
并将其用于文本:
.matchedGeometryEffect(id: "AlbumTitle", in: animation)
就是这样 – 当您再次运行示例时,您将看到两个视图平稳地移动。
以下是最终代码的样子:
struct ContentView: View {
@Namespace private var animation
@State private var isFlipped = false
var body: some View {
VStack {
if isFlipped {
Circle()
.fill(.red)
.frame(width: 44, height: 44)
.matchedGeometryEffect(id: "Shape", in: animation)
Text("Taylor Swift - 1989")
.font(.headline)
.matchedGeometryEffect(id: "AlbumTitle", in: animation)
} else {
Text("Taylor Swift - 1989")
.font(.headline)
.matchedGeometryEffect(id: "AlbumTitle", in: animation)
Circle()
.fill(.blue)
.frame(width: 44, height: 44)
.matchedGeometryEffect(id: "Shape", in: animation)
}
}
.onTapGesture {
withAnimation {
isFlipped.toggle()
}
}
}
}
运行的效果
![图片[2]-如何使用 matchedGeometryEffect() 将一个视图的动画同步到另一个视图-Stewed Noodles 资源](https://img.stewednoodles.com/images/2025/01/14/StewedNoodles20250114100323.gif)
有关更高级的示例,请尝试此操作 – 它借用了 Apple Music
的专辑显示样式,在点击时将小视图扩展到更大的视图。在此示例中,只有文本是动画的,因为它正在更改位置:
struct ContentView: View {
@Namespace private var animation
@State private var isZoomed = false
var frame: Double {
isZoomed ? 300 : 44
}
var body: some View {
VStack {
Spacer()
VStack {
HStack {
RoundedRectangle(cornerRadius: 10)
.fill(.blue)
.frame(width: frame, height: frame)
.padding(.top, isZoomed ? 20 : 0)
if isZoomed == false {
Text("Taylor Swift - 1989")
.matchedGeometryEffect(id: "AlbumTitle", in: animation)
.font(.headline)
Spacer()
}
}
if isZoomed == true {
Text("Taylor Swift - 1989")
.matchedGeometryEffect(id: "AlbumTitle", in: animation)
.font(.headline)
.padding(.bottom, 60)
Spacer()
}
}
.onTapGesture {
withAnimation {
isZoomed.toggle()
}
}
.padding()
.frame(maxWidth: .infinity)
.frame(height: 400)
.background(Color(white: 0.9))
.foregroundStyle(.black)
}
}
}
运行效果
![图片[3]-如何使用 matchedGeometryEffect() 将一个视图的动画同步到另一个视图-Stewed Noodles 资源](https://img.stewednoodles.com/images/2025/01/14/StewedNoodles20250114101319.gif)
暂无评论内容