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

SwiftUI:如何获取.sheet中视图的固有高度并更新其尺寸?

SwiftUI中让Sheet自适应内容固有高度的解决方案

问题背景

我想创建一个自适应内容固有高度的.sheet,尝试通过readSize方法读取视图高度,再用presentationDetents([.height(sheetHeight)])设置自定义高度,但发现初始sheetHeight为0时,视图被限制为0高度,无法获取真实的固有高度。虽然知道confirmationDialog更适合我的场景,但还是想了解.sheet的解决办法。

解决方案

核心思路是先让Sheet不受高度限制地渲染内容,获取到固有高度后,再动态切换为自定义高度的detent,避免初始高度限制导致无法读取真实尺寸。

修改后的完整代码

import SwiftUI

struct ContentView: View {
    @State private var showBottomSheet = false
    @State private var sheetHeight = Double.zero
    @State private var useCustomDetent = false // 控制是否切换到自定义高度
    
    var body: some View {
        Form {
            Button("Show bottom sheet") {
                // 每次弹出前重置状态,避免上次高度影响
                sheetHeight = .zero
                useCustomDetent = false
                showBottomSheet = true
            }
        }
        .sheet(isPresented: $showBottomSheet) {
            BottomSheetView()
                .readSize { newSize in
                    // 只在第一次获取到有效高度时更新
                    guard sheetHeight == .zero, newSize.height > 0 else { return }
                    sheetHeight = newSize.height
                    // 延迟切换detent,避免布局循环
                    DispatchQueue.main.async {
                        useCustomDetent = true
                    }
                }
                .presentationDetents(useCustomDetent ? [.height(sheetHeight)] : [.automatic])
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct BottomSheetView: View {
    var body: some View {
        Form {
            Button("Button 1") { /*Perform stuff*/ }
            Button("Button 2") { /*Perform other stuff*/ }
        }
    }
}

struct SizePreferenceKey: PreferenceKey {
  static var defaultValue: CGSize = .zero
  static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

extension View {
  func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
    background(
      GeometryReader { geometryProxy in
        Color.clear
          .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
      }
    )
    .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
  }
}

关键逻辑说明

  1. 状态变量useCustomDetent:初始为false,让Sheet使用.automatic detent,确保内容能自由布局,不受高度限制
  2. 高度读取控制:仅在第一次获取到有效高度时更新sheetHeight,避免重复触发布局更新
  3. 延迟切换detent:用DispatchQueue.main.async确保视图完成布局后再切换到自定义高度,防止出现布局循环或视觉闪烁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:02:49