所以我有一个类,其中包含一个名为keyboardHeight的已发布变量,用于检索keyboardHeight的值:
class KeyboardHeightHelper: ObservableObject {
@Published var keyboardHeight: Double = 0
init() {
listenForKeyboardNotifications()
}
private func listenForKeyboardNotifications() {
NotificationCenter.default.addObserver(
forName: UIResponder.keyboardDidShowNotification,
object: nil,
queue: .main
) { notification in
guard
let userInfo = notification.userInfo,
let keyboardRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
else { return }
self.keyboardHeight = keyboardRect.height
}
NotificationCenter.default.addObserver(
forName: UIResponder.keyboardDidHideNotification,
object: nil,
queue: .main)
{ _ in
self.keyboardHeight = 0
}
}
}
然后,在 ContentView 中,我只有一个 TextField,当您开始/停止编辑字段时,它应该打印键盘高度:
import SwiftUI
struct ContentView: View {
@State var textFieldText = ""
@ObservedObject var keyboardHeightHelper = KeyboardHeightHelper()
var body: some View {
VStack {
TextField("Text field",
text: $textFieldText, onEditingChanged: { _ in print("the keyboard height is \(self.keyboardHeightHelper.keyboardHeight)") })
}
}
}
我遇到的问题是这样的:当我不编辑文本字段然后单击它时,它会打印键盘高度为0.0(我猜这是因为它在呈现键盘之前获取了keyboardHeight值,所以当时的高度为 0.0,因为看不到键盘)。当我按回车键并且键盘关闭时,键盘的高度(对于 iPhone 8 模拟器)将打印为正确的值 260.0。我的问题是当我开始编辑时如何访问键盘的值?
试试这个。您只需使用修饰符即可将其集成到 SwiftUI 视图中:
extension UIResponder {
static var currentFirstResponder: UIResponder? {
_currentFirstResponder = nil
UIApplication.shared.sendAction(#selector(UIResponder.findFirstResponder(_:)), to: nil, from: nil, for: nil)
return _currentFirstResponder
}
private static weak var _currentFirstResponder: UIResponder?
@objc private func findFirstResponder(_ sender: Any) {
UIResponder._currentFirstResponder = self
}
var globalFrame: CGRect? {
guard let view = self as? UIView else { return nil }
return view.superview?.convert(view.frame, to: nil)
}
}
extension Publishers {
static var keyboardHeight: AnyPublisher<CGFloat, Never> {
let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification)
.map { $0.keyboardHeight }
let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
return MergeMany(willShow, willHide)
.eraseToAnyPublisher()
}
}
extension Notification {
var keyboardHeight: CGFloat {
return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
}
}
struct KeyboardAdaptive: ViewModifier {
@State private var bottomPadding: CGFloat = 0
func body(content: Content) -> some View {
GeometryReader { geometry in
content
.padding(.bottom, self.bottomPadding)
.onReceive(Publishers.keyboardHeight) { keyboardHeight in
let keyboardTop = geometry.frame(in: .global).height - keyboardHeight
let focusedTextInputBottom = UIResponder.currentFirstResponder?.globalFrame?.maxY ?? 0
self.bottomPadding = max(0, focusedTextInputBottom - keyboardTop - geometry.safeAreaInsets.bottom)
}
.animation(.easeOut(duration: 0.16))
}
}
}
extension View {
func keyboardAdaptive() -> some View {
ModifiedContent(content: self, modifier: KeyboardAdaptive())
}
}
用途:
struct ContentView: View {
@State private var text = ""
var body: some View {
VStack {
Spacer()
TextField("Enter something", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
.padding()
.keyboardAdaptive()//note this
}
}
归功于多个在线资源。
.onEditingChanged
不是读取键盘高度的合适位置,因为您在单击 TextField 时立即收到此回调,因此尚未显示键盘(因此,没有收到通知)。
相反,您可以显式侦听您的
keyboardHeight
属性发布者,并在其更改时准确收到通知(同步在键盘通知上执行的操作,因此及时)
这是一个解决方案(使用 Xcode 12 / iOS 14 测试)
VStack {
TextField("Text field",
text: $textFieldText, onEditingChanged: { _ in })
.onReceive(keyboardHeightHelper.$keyboardHeight) { value in
print("the keyboard height is \(value)")
}
}