SwiftUI问题:如何解决视图过渡时Y轴动画快于X轴的问题?
问题:SwiftUI矩形展开过渡动画不同步
我尝试在两个SwiftUI视图间实现向外展开/向内收缩的过渡动画:从包含小矩形的Playground5过渡到同色全屏矩形的Playground6。目前过渡能生效,但动画异常——矩形展开时上下方向先完成,左右方向滞后,无法同步完成。
原代码如下:
import SwiftUI struct Playground5: View { @State private var expandRectangle = false @Namespace private var namespace var body: some View { VStack { if expandRectangle { Playground6(expandRectangle: $expandRectangle, namespace: namespace) // .matchedGeometryEffect(id: "rectangle", in: namespace) } else { Rectangle() .foregroundColor(Color.red) .frame(width: 200, height: 400) // .frame(width: expandRectangle ? 400 : 200, height: expandRectangle ? 600 : 400) .onTapGesture { withAnimation { expandRectangle.toggle() } } .matchedGeometryEffect(id: "rectangle", in: namespace, properties: .position, anchor: .center) } } .ignoresSafeArea(.all) } } struct Playground6: View { @Binding var expandRectangle: Bool var namespace: Namespace.ID @Namespace private var namespace2 var body: some View { // ZStack { Rectangle() .onTapGesture { withAnimation { expandRectangle.toggle() } } .foregroundColor(Color.red) .frame(maxWidth: .infinity, maxHeight: .infinity) .ignoresSafeArea(.all) .matchedGeometryEffect(id: "rectangle",in: namespace) } }
解决思路
- 统一
matchedGeometryEffect配置:两个视图的matchedGeometryEffect参数必须完全一致,原代码中Playground5额外指定了properties: .position和anchor: .center,这会导致动画计算逻辑不一致,移除这些额外参数即可让动画同步。 - 简化布局约束:移除Playground6中Rectangle上的
ignoresSafeArea,父容器已经设置该属性,重复设置会干扰布局计算。 - 使用ZStack替代VStack:VStack的布局特性会给子视图添加额外的垂直约束,改用ZStack作为容器可以让两个视图处于同一布局上下文,避免约束导致的动画不同步。
修正后的代码
import SwiftUI struct Playground5: View { @State private var expandRectangle = false @Namespace private var namespace var body: some View { ZStack { // 改用ZStack作为容器 if expandRectangle { Playground6(expandRectangle: $expandRectangle, namespace: namespace) } else { Rectangle() .foregroundColor(Color.red) .frame(width: 200, height: 400) .onTapGesture { withAnimation(.easeInOut(duration: 0.5)) { // 可指定动画曲线和时长 expandRectangle.toggle() } } .matchedGeometryEffect(id: "rectangle", in: namespace) // 统一配置 } } .ignoresSafeArea(.all) } } struct Playground6: View { @Binding var expandRectangle: Bool var namespace: Namespace.ID var body: some View { Rectangle() .foregroundColor(Color.red) .frame(maxWidth: .infinity, maxHeight: .infinity) .onTapGesture { withAnimation(.easeInOut(duration: 0.5)) { expandRectangle.toggle() } } .matchedGeometryEffect(id: "rectangle", in: namespace) // 统一配置 } }
内容的提问来源于stack exchange,提问作者N G
相关产品推荐
相关产品推荐

