Files
suixinkan_uikit/suixinkan/UI/Common/KeyboardAvoidingDialogView.swift

106 lines
3.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// KeyboardAvoidingDialogView.swift
// suixinkan
//
import SnapKit
import UIKit
///
class KeyboardAvoidingDialogView: UIView {
///
var keyboardAvoidingContentView: UIView?
/// centerY
var keyboardAvoidingCenterYConstraint: Constraint?
///
var keyboardAvoidingMinimumSpacing: CGFloat = AppSpacing.md
private var keyboardObservers: [NSObjectProtocol] = []
override init(frame: CGRect) {
super.init(frame: frame)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
unregisterKeyboardObservers()
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
unregisterKeyboardObservers()
} else {
registerKeyboardObservers()
}
}
private func registerKeyboardObservers() {
unregisterKeyboardObservers()
let center = NotificationCenter.default
keyboardObservers = [
center.addObserver(
forName: UIResponder.keyboardWillChangeFrameNotification,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleKeyboardNotification(notification)
},
center.addObserver(
forName: UIResponder.keyboardWillHideNotification,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleKeyboardNotification(notification)
}
]
}
private func unregisterKeyboardObservers() {
keyboardObservers.forEach(NotificationCenter.default.removeObserver)
keyboardObservers.removeAll()
}
private func handleKeyboardNotification(_ notification: Notification) {
layoutIfNeeded()
guard let userInfo = notification.userInfo else { return }
let duration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.25
let curveRaw = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue
?? UInt(UIView.AnimationCurve.easeInOut.rawValue)
let options = UIView.AnimationOptions(rawValue: curveRaw << 16)
keyboardAvoidingCenterYConstraint?.update(offset: keyboardAvoidanceOffset(from: userInfo))
UIView.animate(withDuration: duration, delay: 0, options: options) {
self.layoutIfNeeded()
}
}
private func keyboardAvoidanceOffset(from userInfo: [AnyHashable: Any]) -> CGFloat {
guard
let contentView = keyboardAvoidingContentView,
let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else {
return 0
}
let keyboardFrame = convert(keyboardFrameValue.cgRectValue, from: nil)
guard keyboardFrame.minY < bounds.height else { return 0 }
let contentHeight = contentView.bounds.height
let baseMinY = bounds.midY - contentHeight / 2
let baseMaxY = bounds.midY + contentHeight / 2
let desiredBottom = keyboardFrame.minY - keyboardAvoidingMinimumSpacing
let neededShift = max(0, baseMaxY - desiredBottom)
let maxShift = max(0, baseMinY - keyboardAvoidingMinimumSpacing)
return -min(neededShift, maxShift)
}
}