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

SwiftUI中如何让Sheet高度适配内容+键盘高度?

解决方案

要实现Sheet默认适配内容高度、键盘弹出时自动扩展高度的效果,你可以通过捕获内容真实高度+监听键盘高度的组合方式动态调整presentationDetents,具体实现如下:

1. 定义PreferenceKey捕获内容高度

先创建一个PreferenceKey,用来收集Sheet内内容的实际高度:

struct ContentHeightKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = max(value, nextValue())
    }
}

2. 修改Sheet视图实现动态高度

在Sheet的内容视图中,通过background里的GeometryReader获取内容高度,同时监听键盘弹出/收起事件更新键盘高度,最终动态计算Sheet总高度:

struct TestView: View {
    @State private var showSheet: Bool = false
    @State private var textfieldInput: String = ""
    @State private var contentHeight: CGFloat = 0
    @State private var keyboardHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            Button("Show Sheet") {
                showSheet.toggle()
            }
            .sheet(isPresented: $showSheet) {
                VStack(alignment: .leading) {
                    TextField("This is a textfield", text: $textfieldInput)
                        .bold()
                        .font(.title3)
                    Text("More (variable) content underneath the textfield")
                }
                .padding(20)
                .border(Color.red)
                // 捕获内容真实高度
                .background(
                    GeometryReader { geo in
                        Color.clear
                            .preference(key: ContentHeightKey.self, value: geo.size.height)
                    }
                )
                .onPreferenceChange(ContentHeightKey.self) { newValue in
                    contentHeight = newValue
                }
                // 动态设置Sheet高度
                .presentationDetents([.height(contentHeight + keyboardHeight)])
                // 监听键盘弹出并同步动画
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
                    guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                    guard let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else { return }
                    withAnimation(.easeOut(duration: duration)) {
                        keyboardHeight = frame.height
                    }
                }
                // 监听键盘收起并同步动画
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { notification in
                    guard let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else { return }
                    withAnimation(.easeOut(duration: duration)) {
                        keyboardHeight = 0
                    }
                }
            }
        }
    }
}

关键说明

  • 你之前用根视图GeometryReader失效的原因:根视图的GeometryReader获取的是Sheet初始分配的可用空间,而非内容的真实高度,导致Sheet高度不足。
  • 动画优化:通过键盘通知里的动画时长参数,让Sheet高度变化和键盘弹出/收起动画同步,提升流畅度。
  • 兼容性:该方案适配iOS 15+,如果是iOS 16+,也可以结合.presentationDetents([.height(contentHeight), .dynamic])简化,但动态计算高度的方式兼容性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 04:30:07