You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:15:23