Files
suixinkan_uikit/Pods/IQKeyboardNotification/IQKeyboardNotification/Classes/IQKeyboardNotification.swift

173 lines
6.1 KiB
Swift

//
// IQKeyboardNotification.swift
// https://github.com/hackiftekhar/IQKeyboardNotification
// 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
import Combine
@available(iOSApplicationExtension, unavailable)
@MainActor
@objcMembers public final class IQKeyboardNotification: NSObject {
private var storage: Set<AnyCancellable> = []
private var eventObservers: [IQKeyboardInfo.Event: [AnyHashable: SizeCompletion]] = [:]
public private(set) var oldKeyboardInfo: IQKeyboardInfo
public private(set) var keyboardInfo: IQKeyboardInfo {
didSet {
guard keyboardInfo != oldValue else { return }
oldKeyboardInfo = oldValue
sendKeyboardInfo(info: keyboardInfo)
}
}
public var isVisible: Bool {
keyboardInfo.isVisible
}
public var frame: CGRect {
keyboardInfo.endFrame
}
public override init() {
keyboardInfo = IQKeyboardInfo(notification: nil, event: .didHide)
oldKeyboardInfo = keyboardInfo
super.init()
// Registering for keyboard notification.
for event in IQKeyboardInfo.Event.allCases {
NotificationCenter.default.publisher(for: event.notification)
.map({ IQKeyboardInfo(notification: $0, event: event) })
.sink(receiveValue: { [weak self] keyboardInfo in
self?.keyboardInfo = keyboardInfo
})
.store(in: &storage)
}
}
public func animate(alongsideTransition transition: @escaping () -> Void, completion: (() -> Void)? = nil) {
keyboardInfo.animate(alongsideTransition: transition, completion: completion)
}
}
@available(iOSApplicationExtension, unavailable)
@MainActor
public extension IQKeyboardNotification {
typealias SizeCompletion = (_ event: IQKeyboardInfo.Event, _ endFrame: CGRect) -> Void
func subscribe(for events: [IQKeyboardInfo.Event],
identifier: AnyHashable, changeHandler: @escaping SizeCompletion) {
for event in events {
var existingObservers: [AnyHashable: SizeCompletion] = eventObservers[event] ?? [:]
existingObservers[identifier] = changeHandler
eventObservers[event] = existingObservers
}
// If current event is the one user is subscribed to, then call changeHandler immediately for the first time.
if events.contains(keyboardInfo.event) {
changeHandler(keyboardInfo.event, keyboardInfo.endFrame)
}
}
func unsubscribe(for events: [IQKeyboardInfo.Event], identifier: AnyHashable) {
for event in events {
var existingObservers: [AnyHashable: SizeCompletion] = eventObservers[event] ?? [:]
existingObservers[identifier] = nil
eventObservers[event] = existingObservers
}
}
func isSubscribed(for event: IQKeyboardInfo.Event? = nil, identifier: AnyHashable) -> Bool {
if let event = event {
guard let observers = eventObservers[event], !observers.isEmpty else { return false }
return observers[identifier] != nil
} else {
for event in IQKeyboardInfo.Event.allCases {
let observers = eventObservers[event] ?? [:]
if observers[identifier] != nil {
return true
}
}
return false
}
}
private func sendKeyboardInfo(info: IQKeyboardInfo) {
guard let observers = eventObservers[info.event], !observers.isEmpty else { return }
let endFrame: CGRect = info.endFrame
for block in observers.values {
block(info.event, endFrame)
}
}
}
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc public extension IQKeyboardNotification {
var oldKeyboardInfoObjc: IQKeyboardInfoObjC { IQKeyboardInfoObjC(wrappedValue: oldKeyboardInfo) }
var keyboardInfoObjc: IQKeyboardInfoObjC { IQKeyboardInfoObjC(wrappedValue: keyboardInfo) }
func subscribe(identifier: AnyHashable, changeHandler: @escaping SizeCompletion) {
subscribe(for: IQKeyboardInfo.Event.allCases, identifier: identifier, changeHandler: changeHandler)
}
func unsubscribe(identifier: AnyHashable) {
unsubscribe(for: IQKeyboardInfo.Event.allCases, identifier: identifier)
}
func isSubscribed(identifier: AnyHashable) -> Bool {
isSubscribed(for: nil, identifier: identifier)
}
}
// MARK: Deprecated
@available(iOSApplicationExtension, unavailable)
@objc public extension IQKeyboardNotification {
// MARK: Deprecated
@available(*, unavailable, renamed: "isVisible")
var keyboardShowing: Bool { isVisible }
@available(*, unavailable, renamed: "subscribe(identifier:changeHandler:)")
func registerSizeChange(identifier: AnyHashable, changeHandler: @escaping SizeCompletion) {
subscribe(identifier: identifier, changeHandler: changeHandler)
}
@available(*, unavailable, renamed: "unsubscribe(identifier:)")
func unregisterSizeChange(identifier: AnyHashable) {
unsubscribe(identifier: identifier)
}
}