| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- //
- // LNKeyboardManager.swift
- // Lanu
- //
- // Created by OneeChan on 2026/1/5.
- //
- import Foundation
- protocol LNKeyboardNotify {
- func onKeyboardWillShow(curInput: UIView?, keyboardHeight: CGFloat)
- func onKeyboardShow(curInput: UIView?, keyboardHeight: CGFloat)
- func onKeyboardDidShow(curInput: UIView?, keyboardHeight: CGFloat)
-
- func onKeyboardWillHide(curInput: UIView?)
- func onKeyboardHide(curInput: UIView?)
- func onKeyboardDidHide(curInput: UIView?)
- }
- extension LNKeyboardNotify {
- func onKeyboardWillShow(curInput: UIView?, keyboardHeight: CGFloat) {}
- func onKeyboardShow(curInput: UIView?, keyboardHeight: CGFloat) {}
- func onKeyboardDidShow(curInput: UIView?, keyboardHeight: CGFloat) {}
-
- func onKeyboardWillHide(curInput: UIView?) {}
- func onKeyboardHide(curInput: UIView?) {}
- func onKeyboardDidHide(curInput: UIView?) {}
- }
- class LNKeyboardManager {
- static let shared = LNKeyboardManager()
-
- private weak var curInput: UIView?
- var isEditing: Bool {
- curInput != nil
- }
-
- private init() {
- addFirstResponderObservers()
- addKeyboardObservers()
- }
-
- private func addKeyboardObservers() {
- NotificationCenter.default.addObserver(
- forName: UIResponder.keyboardWillShowNotification,
- object: nil, queue: .main
- ) { [weak self] notify in
- guard let self else { return }
-
- guard let userInfo = notify.userInfo,
- let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
- else { return }
- let keyboardHeight = CGRectGetHeight(keyboardFrame)
-
- // 获取键盘动画时长(默认0.25秒)
- let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0.25
-
- // 获取键盘动画曲线(默认UIView.AnimationCurve.easeInOut)
- let animationCurveRawValue = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int ?? UIView.AnimationCurve.easeInOut.rawValue
-
- let visibleView = (curInput as? UITextInput)?.visibleView ?? curInput
-
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardWillShow(curInput: visibleView, keyboardHeight: keyboardHeight)
- }
-
- // 应用动画参数调整UI(使视图动画与键盘动画同步)
- UIView.animate(withDuration: animationDuration,
- delay: 0,
- options: UIView
- .AnimationOptions(rawValue: UInt(animationCurveRawValue)),
- animations: {
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardShow(curInput: visibleView, keyboardHeight: keyboardHeight)
- }
- }) { _ in
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardDidShow(curInput: visibleView, keyboardHeight: keyboardHeight)
- }
- }
- }
- NotificationCenter.default.addObserver(
- forName: UIResponder.keyboardWillHideNotification,
- object: nil, queue: .main
- ) { [weak self] notify in
- guard let self else { return }
-
- guard let userInfo = notify.userInfo else { return }
-
- // 获取键盘动画时长(默认0.25秒)
- let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0.25
-
- // 获取键盘动画曲线(默认UIView.AnimationCurve.easeInOut)
- let animationCurveRawValue = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int ?? UIView.AnimationCurve.easeInOut.rawValue
-
- let visibleView = (curInput as? UITextInput)?.visibleView ?? curInput
-
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardWillHide(curInput: visibleView)
- }
- // 应用动画参数调整UI(使视图动画与键盘动画同步)
- UIView.animate(withDuration: animationDuration,
- delay: 0,
- options: UIView
- .AnimationOptions(rawValue: UInt(animationCurveRawValue)),
- animations: {
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardHide(curInput: visibleView)
- }
- }) { _ in
- LNEventDeliver.notifyEvent {
- ($0 as? LNKeyboardNotify)?.onKeyboardDidHide(curInput: visibleView)
- }
- }
- }
- }
-
- private func addFirstResponderObservers() {
- // UITextField
- NotificationCenter.default.addObserver(
- forName: UITextField.textDidBeginEditingNotification,
- object: nil, queue: .main)
- { [weak self] notify in
- guard let self else { return }
- curInput = notify.object as? UITextField
- }
- NotificationCenter.default.addObserver(
- forName: UITextField.textDidEndEditingNotification,
- object: nil, queue: .main)
- { [weak self] notify in
- guard let self else { return }
- curInput = nil
- }
-
- // UITextView
- NotificationCenter.default.addObserver(
- forName: UITextView.textDidBeginEditingNotification,
- object: nil, queue: .main)
- { [weak self] notify in
- guard let self else { return }
- curInput = notify.object as? UITextView
- }
- NotificationCenter.default.addObserver(
- forName: UITextView.textDidEndEditingNotification,
- object: nil, queue: .main)
- { [weak self] notify in
- guard let self else { return }
- curInput = nil
- }
- }
- }
- private struct LNWeakProxy {
- weak var obj: UIView?
- }
- private var LNInputViewVisibleViewKey: UInt8 = 0
- extension UITextInput {
- weak var visibleView: UIView? {
- get {
- let proxy = objc_getAssociatedObject(self, &LNInputViewVisibleViewKey) as? LNWeakProxy
- return proxy?.obj
- }
- set {
- objc_setAssociatedObject(self, &LNInputViewVisibleViewKey, LNWeakProxy(obj: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
- }
- }
- }
|