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

带NavigationStack的动态尺寸Sheet无法正确调整大小问题

问题:动态修改带NavigationStack的Sheet高度后内容显示异常

开发包含NavigationStack的Sheet时,动态修改其高度后,视图无法正常展示内容,只有滚动Sheet后内容才会正确显示。

代码示例

struct SheetWithNavigation: View {
    @EnvironmentObject var router: Router
    
    @State private var sheetDetents: Set<PresentationDetent> = [.height(460)]
    
    var body: some View {
        NavigationStack(path: $router.navigation) {
            VStack {
                Spacer()
                Text("Sheet Presented")
                Spacer()
                
                Button("Navigate to First View") {
                    router.navigate(to: .firstNavigationView)
                }
            }
            .navigationDestination(for: Router.Destination.self) { destination in
                switch destination {
                case .firstNavigationView:
                    FirstNavigationView()
                        .navigationBarBackButtonHidden(true)
                        .onAppear {
                            sheetDetents = [.height(300)]
                        }
                }
            }
        }
        .background(.white)
        .presentationDetents(sheetDetents)
    }
}

struct FirstNavigationView: View {
    var body: some View {
        VStack {
            Spacer()
            Text("First Navigation View")
            Spacer()
            
            Button("Go to second navigation view") {}
        }
        .background(.white)
    }
}

解决方案

这个问题源于Sheet高度变化后,NavigationStack内部的视图布局未及时刷新,导致内容位置计算错误。以下是两种可行的修复方式:

方法1:通过修改ID强制刷新NavigationStack

给NavigationStack绑定一个动态ID,当Sheet高度变化时更新ID,触发视图重建,确保布局重新计算:

struct SheetWithNavigation: View {
    @EnvironmentObject var router: Router
    
    @State private var sheetDetents: Set<PresentationDetent> = [.height(460)]
    @State private var navStackRefreshId = UUID()
    
    var body: some View {
        NavigationStack(path: $router.navigation) {
            VStack {
                Spacer()
                Text("Sheet Presented")
                Spacer()
                
                Button("Navigate to First View") {
                    router.navigate(to: .firstNavigationView)
                }
            }
            .navigationDestination(for: Router.Destination.self) { destination in
                switch destination {
                case .firstNavigationView:
                    FirstNavigationView()
                        .navigationBarBackButtonHidden(true)
                        .onAppear {
                            sheetDetents = [.height(300)]
                        }
                }
            }
        }
        .background(.white)
        .presentationDetents(sheetDetents)
        .id(navStackRefreshId)
        .onChange(of: sheetDetents) { _ in
            navStackRefreshId = UUID()
        }
    }
}

方法2:用动画包裹高度修改触发布局更新

在修改Sheet高度时使用withAnimation,让SwiftUI自动处理布局过渡,确保内容正确适配新高度:

FirstNavigationView()
    .navigationBarBackButtonHidden(true)
    .onAppear {
        withAnimation {
            sheetDetents = [.height(300)]
        }
    }

同时,建议检查目标视图的布局逻辑,避免过度依赖Spacer导致的布局自适应问题,必要时给内容添加明确的尺寸约束。

内容的提问来源于stack exchange,提问作者DiegoQ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:47:21