IQKeyboardManagerSwift/LIsteners/Info/IQKeyboardInfo.swift
//
// IQKeyboardInfo.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-24 Iftekhar Qurashi.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
@available(iOSApplicationExtension, unavailable)
@MainActor
public struct IQKeyboardInfo: Equatable {
nonisolated public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.frame.equalTo(rhs.frame)
}
@objc public enum Name: Int {
case willShow
case didShow
case willHide
case didHide
case willChangeFrame
case didChangeFrame
}
public let name: Name
/** To save keyboard frame. */
public let frame: CGRect
/** To save keyboard animation duration. */
public let animationDuration: TimeInterval
/** To mimic the keyboard animation */
public let animationCurve: UIView.AnimationCurve
public var keyboardShowing: Bool {
frame.height > 0
}
public init(notification: Notification?, name: Name) {
self.name = name
let screenBounds: CGRect
if let screen: UIScreen = notification?.object as? UIScreen {
screenBounds = screen.bounds
} else {
screenBounds = UIScreen.main.bounds
}
if let info: [AnyHashable: Any] = notification?.userInfo {
// Getting keyboard animation.
if let curveValue: Int = info[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int,
let curve: UIView.AnimationCurve = UIView.AnimationCurve(rawValue: curveValue) {
animationCurve = curve
} else {
animationCurve = .easeOut
}
// Getting keyboard animation duration
if let duration: TimeInterval = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,
duration != 0.0 {
animationDuration = duration
} else {
animationDuration = 0.25
}
// Getting UIKeyboardSize.
if var kbFrame: CGRect = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
// If this is floating keyboard
if kbFrame.width < screenBounds.width,
kbFrame.maxY < screenBounds.height {
kbFrame.size = CGSize(width: kbFrame.size.width, height: 0)
} else {
// (Bug ID: #469) (Bug ID: #381) (Bug ID: #1506)
// Calculating actual keyboard covered size respect to window,
// keyboard frame may be different when hardware keyboard is attached
let keyboardHeight = CGFloat.maximum(screenBounds.height - kbFrame.minY, 0)
kbFrame.size = CGSize(width: kbFrame.size.width, height: keyboardHeight)
}
frame = kbFrame
} else {
frame = CGRect(x: 0, y: screenBounds.height, width: screenBounds.width, height: 0)
}
} else {
animationCurve = .easeOut
animationDuration = 0.25
frame = CGRect(x: 0, y: screenBounds.height, width: screenBounds.width, height: 0)
}
}
public func animate(alongsideTransition transition: @escaping () -> Void, completion: (() -> Void)? = nil) {
// if let timing = UIView.AnimationCurve.RawValue(exactly: animationCurve.rawValue),
// let curve = UIView.AnimationCurve(rawValue: timing) {
// let animator = UIViewPropertyAnimator(duration: animationDuration, curve: curve) {
// transition()
// }
// animator.addCompletion { _ in
// completion?()
// }
// animator.isUserInteractionEnabled = true
// animator.startAnimation()
// } else {
var animationOptions: UIView.AnimationOptions = .init(rawValue: UInt(animationCurve.rawValue << 16))
animationOptions.formUnion(.allowUserInteraction)
animationOptions.formUnion(.beginFromCurrentState)
UIView.animate(withDuration: animationDuration, delay: 0,
options: animationOptions,
animations: transition,
completion: { _ in
completion?()
})
// }
}
}