通过 MatchedGeometryEffect 向上滑动视图
Sliding view up by MatchedGeometryEffect
我想使用 .matchedGeometryEffect
实现图像被点击时的向上滑动动画。我只想用它来动画位置变化,因为两个图像的帧是相同的。在此示例中,我将图像替换为黑色矩形,因为它也可以重现。
简化代码:
struct ContentView: View {
@Namespace var namespace
@State var isShowingDetail = false
var body: some View {
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.top)
Spacer()
}
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
.onTapGesture {
changeView()
}
}
}
private func changeView() {
withAnimation(.easeOut(duration: 0.3)){
isShowingDetail.toggle()
}
}
}
视图向上滑动,但它没有正确设置动画,因为它有淡入淡出的效果。我假设它与应用于每个视图的默认淡入淡出过渡有关,我试图设置一个自定义的,但找不到适合这种情况的。
修饰符的位置很重要,对于 matchedGeometryEffect
来说更重要。
这里是固定变体。 Xcode 13.2 / iOS 15.2
var body: some View {
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.top)
// !! applied here !!
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
Spacer()
}
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
// !! applied here !!
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.onTapGesture {
changeView()
}
}
}
我想通了 blink/fade 效果移除部分。如我所料,它与在没有显式过渡时适用的默认淡入淡出过渡有关。我为这种情况找到了合适的:
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.edgesIgnoringSafeArea(.top)
Spacer()
}
.transition(.offset()) // applied here
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.transition(.offset()) // applied here
.onTapGesture {
changeView()
}
}
我想使用 .matchedGeometryEffect
实现图像被点击时的向上滑动动画。我只想用它来动画位置变化,因为两个图像的帧是相同的。在此示例中,我将图像替换为黑色矩形,因为它也可以重现。
简化代码:
struct ContentView: View {
@Namespace var namespace
@State var isShowingDetail = false
var body: some View {
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.top)
Spacer()
}
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
.onTapGesture {
changeView()
}
}
}
private func changeView() {
withAnimation(.easeOut(duration: 0.3)){
isShowingDetail.toggle()
}
}
}
视图向上滑动,但它没有正确设置动画,因为它有淡入淡出的效果。我假设它与应用于每个视图的默认淡入淡出过渡有关,我试图设置一个自定义的,但找不到适合这种情况的。
修饰符的位置很重要,对于 matchedGeometryEffect
来说更重要。
这里是固定变体。 Xcode 13.2 / iOS 15.2
var body: some View {
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.top)
// !! applied here !!
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
Spacer()
}
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
// !! applied here !!
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.onTapGesture {
changeView()
}
}
}
我想通了 blink/fade 效果移除部分。如我所料,它与在没有显式过渡时适用的默认淡入淡出过渡有关。我为这种情况找到了合适的:
if isShowingDetail {
VStack {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.edgesIgnoringSafeArea(.top)
Spacer()
}
.transition(.offset()) // applied here
.onTapGesture {
changeView()
}
} else {
Rectangle()
.foregroundColor(.black)
.aspectRatio(contentMode: .fit)
.matchedGeometryEffect(id: "image", in: namespace, properties: .position)
.transition(.offset()) // applied here
.onTapGesture {
changeView()
}
}