【问题标题】:Retrieving keyboard height when textfield editing starts in SwiftUI在 SwiftUI 中开始文本字段编辑时检索键盘高度
【发布时间】:2020-11-16 00:22:38
【问题描述】:

所以我有一个类,其中包含一个名为keyboardHeight 的已发布变量,用于检索keyboardHeight 的值:

import UIKit

class KeyboardHeightHelper: ObservableObject {
@Published var keyboardHeight: CGFloat = 0

init() {
    self.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) { (notification) 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 的正确值。我的问题是当我开始编辑时如何访问键盘的值?

【问题讨论】:

  • @Subha_26 好吧,我真的不想要填充——我只需要访问 CGFloat 值,看起来这个问题只是添加了填充,如果我说实话,代码超出了我的范围所以如果你真的可以正确访问 CGFloat 值,我很抱歉

标签: swift keyboard swiftui textfield editing


【解决方案1】:

试试这个。您可以只使用修饰符将其集成到 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
    }
}

归功于多个在线资源。

【讨论】:

  • 嗨,Subha,我真的不想像之前说的那样添加填充——我只想能够访问keyboardHeight 的值,而不是真正添加填充。
【解决方案2】:

.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)")
        }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2017-06-10
    • 2012-12-07
    • 2021-09-02
    • 2019-01-12
    • 1970-01-01
    • 2017-12-04
    相关资源
    最近更新 更多