SwiftUI文本输入框被键盘遮挡的问题
SwiftUI文本输入框被键盘遮挡的问题

SwiftUI文本输入框被键盘遮挡的问题

在iOS中,如果文本输入框距离底部的位置比较低,当点击输入框并弹出键盘时,输入框存在被键盘遮挡的情况。

解决方案

监听键盘高度,当键盘弹出时,给视图底部添加padding,将内容推上来。

ViewModefier代码:

import Combine
import SwiftUI

struct KeyboardAdaptive: ViewModifier {
    @State private var keyboardHeight: CGFloat = 0

    func body(content: Content) -> some View {
        content
            .padding(.bottom, keyboardHeight)
            .animation(.easeOut(duration: 0.25), value: keyboardHeight)
            .onReceive(Publishers.keyboardHeight) { height in
                keyboardHeight = height
            }
    }
}

extension Publishers {
    static var keyboardHeight: AnyPublisher<CGFloat, Never> {
        let willShow = NotificationCenter.default.publisher(
            for: UIResponder.keyboardWillShowNotification
        )
        .map { $0.keyboardHeight }

        let willHide = NotificationCenter.default.publisher(
            for: UIResponder.keyboardWillHideNotification
        )
        .map { _ in CGFloat(0) }

        return MergeMany(willShow, willHide)
            .eraseToAnyPublisher()
    }
}

extension Notification {
    var keyboardHeight: CGFloat {
        (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
    }
}

在SwiftUI中,使用modifer修饰符修饰视图:

VStack {
    Image("xxx")
    TextField("输入…", text: $text)
        .padding()
}
.modifier(KeyboardAdaptive())

当文本输入框被点击时,弹出键盘,视图的底部padding增高,将文本输入框显示到屏幕上。

代码解析

1、ViewModifier

struct KeyboardAdaptive: ViewModifier {
    @State private var keyboardHeight: CGFloat = 0

    func body(content: Content) -> some View {
        content
            .padding(.bottom, keyboardHeight)
            .animation(.easeOut(duration: 0.25), value: keyboardHeight)
            .onReceive(Publishers.keyboardHeight) { height in
                keyboardHeight = height
            }
    }
}

ViewModifier修饰视图,当keyboardHeight发生改变话,会增加视图的底部padding。

使用onReceive订阅键盘高度变化,当收到新的键盘高度时,更新keyboardHeight,从而加高视图的底部,显示被键盘遮挡的输入框。

2、扩展Publishers

extension Publishers {
    static var keyboardHeight: AnyPublisher<CGFloat, Never> {
        let willShow = NotificationCenter.default.publisher(
            for: UIResponder.keyboardWillShowNotification
        )
        .map { $0.keyboardHeight }

        let willHide = NotificationCenter.default.publisher(
            for: UIResponder.keyboardWillHideNotification
        )
        .map { _ in CGFloat(0) }

        return MergeMany(willShow, willHide)
            .eraseToAnyPublisher()
    }
}

扩展Publishers(发布者),当键盘发生改变时,UIKit发送通知:

键盘即将出现:keyboardWillShowNotification

键盘即将消失:keyboardWillHideNotification

这段代码将UIKit的通知转换成一个 Swift Combine 的Publisher,检测键盘高度发送变化,最后使用MergeMany将两个流合并,得到当前键盘高度的Publisher。

3、扩展Notification通知

extension Notification {
    var keyboardHeight: CGFloat {
        (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
    }
}

从通知的userInfo中获取键盘最终位置的frame,并且读取它的高度。

4、整个代码调用流程

当点击输入框时,弹出键盘 → UIKit发送键盘变化通知 → Combine捕获并读取高度 → Publisher发送高度 → KeyboardAdaptive收到并更新keyboardHeight → View调整底部padding。

当键盘隐藏时 → Publisher发送高度0 → View底部padding回到0 → View恢复正常。

相关文章

1、Apple处理异步任务的Combine框架:https://fangjunyu.com/2024/12/01/apple%e5%a4%84%e7%90%86%e5%bc%82%e6%ad%a5%e4%bb%bb%e5%8a%a1%e7%9a%84combine%e6%a1%86%e6%9e%b6/

2、SwiftUI响应Combine的onReceive:https://fangjunyu.com/2025/07/15/swiftui%e5%93%8d%e5%ba%94combine%e7%9a%84onreceive/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注