mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-21 03:43:16 +09:00
126 lines
5 KiB
Swift
126 lines
5 KiB
Swift
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import UIKit
|
|
import Foundation
|
|
|
|
/**
|
|
* The keyboard state at the time of notification.
|
|
*/
|
|
public struct KeyboardState {
|
|
public let animationDuration: Double
|
|
public let animationCurve: UIViewAnimationCurve
|
|
private let userInfo: [AnyHashable: Any]
|
|
|
|
fileprivate init(_ userInfo: [AnyHashable: Any]) {
|
|
self.userInfo = userInfo
|
|
animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
|
|
// HACK: UIViewAnimationCurve doesn't expose the keyboard animation used (curveValue = 7),
|
|
// so UIViewAnimationCurve(rawValue: curveValue) returns nil. As a workaround, get a
|
|
// reference to an EaseIn curve, then change the underlying pointer data with that ref.
|
|
var curve = UIViewAnimationCurve.easeIn
|
|
if let curveValue = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int {
|
|
NSNumber(value: curveValue as Int).getValue(&curve)
|
|
}
|
|
self.animationCurve = curve
|
|
}
|
|
|
|
/// Return the height of the keyboard that overlaps with the specified view. This is more
|
|
/// accurate than simply using the height of UIKeyboardFrameBeginUserInfoKey since for example
|
|
/// on iPad the overlap may be partial or if an external keyboard is attached, the intersection
|
|
/// height will be zero. (Even if the height of the *invisible* keyboard will look normal!)
|
|
public func intersectionHeightForView(_ view: UIView) -> CGFloat {
|
|
if let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
|
|
let keyboardFrame = keyboardFrameValue.cgRectValue
|
|
let convertedKeyboardFrame = view.convert(keyboardFrame, from: nil)
|
|
let intersection = convertedKeyboardFrame.intersection(view.bounds)
|
|
return intersection.size.height
|
|
}
|
|
return 0
|
|
}
|
|
}
|
|
|
|
public protocol KeyboardHelperDelegate: class {
|
|
func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState)
|
|
func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState)
|
|
func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState)
|
|
}
|
|
|
|
/**
|
|
* Convenience class for observing keyboard state.
|
|
*/
|
|
open class KeyboardHelper: NSObject {
|
|
open var currentState: KeyboardState?
|
|
|
|
fileprivate var delegates = [WeakKeyboardDelegate]()
|
|
|
|
open class var defaultHelper: KeyboardHelper {
|
|
struct Singleton {
|
|
static let instance = KeyboardHelper()
|
|
}
|
|
return Singleton.instance
|
|
}
|
|
|
|
/**
|
|
* Starts monitoring the keyboard state.
|
|
*/
|
|
open func startObserving() {
|
|
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
|
|
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
|
|
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
|
|
}
|
|
|
|
deinit {
|
|
NotificationCenter.default.removeObserver(self)
|
|
}
|
|
|
|
/**
|
|
* Adds a delegate to the helper.
|
|
* Delegates are weakly held.
|
|
*/
|
|
open func addDelegate(_ delegate: KeyboardHelperDelegate) {
|
|
// Reuse any existing slots that have been deallocated.
|
|
for weakDelegate in delegates where weakDelegate.delegate == nil {
|
|
weakDelegate.delegate = delegate
|
|
return
|
|
}
|
|
|
|
delegates.append(WeakKeyboardDelegate(delegate))
|
|
}
|
|
|
|
func SELkeyboardWillShow(_ notification: Notification) {
|
|
if let userInfo = notification.userInfo {
|
|
currentState = KeyboardState(userInfo)
|
|
for weakDelegate in delegates {
|
|
weakDelegate.delegate?.keyboardHelper(self, keyboardWillShowWithState: currentState!)
|
|
}
|
|
}
|
|
}
|
|
|
|
func SELkeyboardDidShow(_ notification: Notification) {
|
|
if let userInfo = notification.userInfo {
|
|
currentState = KeyboardState(userInfo)
|
|
for weakDelegate in delegates {
|
|
weakDelegate.delegate?.keyboardHelper(self, keyboardDidShowWithState: currentState!)
|
|
}
|
|
}
|
|
}
|
|
|
|
func SELkeyboardWillHide(_ notification: Notification) {
|
|
if let userInfo = notification.userInfo {
|
|
currentState = KeyboardState(userInfo)
|
|
for weakDelegate in delegates {
|
|
weakDelegate.delegate?.keyboardHelper(self, keyboardWillHideWithState: currentState!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private class WeakKeyboardDelegate {
|
|
weak var delegate: KeyboardHelperDelegate?
|
|
|
|
init(_ delegate: KeyboardHelperDelegate) {
|
|
self.delegate = delegate
|
|
}
|
|
}
|