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

SwiftUI中键盘弹出时如何实现整个视图上移?

SwiftUI自定义Sheet键盘弹出时视图上推解决方案

问题描述

应用中自定义Sheet内的TextField点击弹出键盘时,视图显示异常(截图:输入图片描述),需要实现键盘弹出时将整个Sheet视图向上推动,但常规方案未生效。

解决方案

核心思路是监听键盘高度变化,动态调整Sheet的偏移量,同时修正Sheet的布局设置以响应安全区域变化:

修改后的CustomSheet代码

import SwiftUI
import Design
import Utilities

public struct CustomSheet<Item: Hashable, Content: View>: View {
    private let size: CGSize
    private var item: Binding<Item?>
    private var content: (Item) -> Content
    
    // 存储键盘高度,用于动态调整视图偏移
    @State private var keyboardHeight: CGFloat = 0
    
    public init(
        size: CGSize,
        item: Binding<Item?>,
        @ViewBuilder content: @escaping (Item) -> Content
    ) {
        self.size = size
        self.item = item
        self.content = content
    }
    
    public var body: some View {
        ZStack(alignment: .bottom) {
            background
            
            VStack(spacing: 30) {
                Button {
                    withAnimation {
                        item.wrappedValue = nil
                    }
                } label: {
                    Image(systemName: "xmark")
                        .tint(Colors.jaffa)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
                .padding(20)
                
                if let item = item.wrappedValue {
                    content(item)
                }
            }
            .padding(.horizontal)
            .frame(width: size.width, height: size.height * 0.55)
            .background {
                RoundedRectangle(cornerRadius: 50)
                    .fill(Colors.white)
            }
            // 动态计算偏移:显示时根据键盘高度上移,隐藏时滑出屏幕
            .offset(y: item.wrappedValue != nil ? 
                   (keyboardHeight > 0 ? -keyboardHeight : 0) : 
                   size.height * 1)
            // 监听键盘弹出/收起事件
            .onAppear {
                let showObserver = NotificationCenter.default.addObserver(
                    forName: UIResponder.keyboardWillShowNotification,
                    object: nil,
                    queue: .main
                ) { notification in
                    guard let userInfo = notification.userInfo,
                          let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.25
                    
                    withAnimation(.easeInOut(duration: animationDuration)) {
                        keyboardHeight = keyboardFrame.height
                    }
                }
                
                let hideObserver = NotificationCenter.default.addObserver(
                    forName: UIResponder.keyboardWillHideNotification,
                    object: nil,
                    queue: .main
                ) { notification in
                    let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.25
                    
                    withAnimation(.easeInOut(duration: animationDuration)) {
                        keyboardHeight = 0
                    }
                }
                
                // 存储观察者,避免内存泄漏
                NotificationCenter.default.addObserver(self, selector: #selector(removeObservers), name: UIApplication.willTerminateNotification, object: nil)
            }
            .onDisappear {
                removeObservers()
            }
        }
    }
    
    @objc private func removeObservers() {
        NotificationCenter.default.removeObserver(self)
    }
}

extension CustomSheet {
    private var background: some View {
        Rectangle()
            .fill(.ultraThinMaterial)
            .ignoresSafeArea()
            .opacity((item.wrappedValue != nil) ? 1 : 0)
    }
}

关键修改说明

  1. 添加键盘高度监听:通过NotificationCenter监听键盘的弹出和收起事件,获取键盘高度和动画参数,同步更新keyboardHeight状态。
  2. 动态调整偏移量:修改Sheet的offset属性,当键盘弹出时,将Sheet向上偏移对应高度,避免被键盘遮挡;键盘收起时恢复原位。
  3. 修正背景布局:移除背景的edgesIgnoringSafeArea(.bottom),让Sheet正确响应底部安全区域变化,避免布局错位。
  4. 内存泄漏防护:在视图消失或应用终止时移除通知观察者,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:47:01