diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index 7ba6c212..e8e33dbc 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -62,6 +62,8 @@ class AdaptiveModalManager: NSObject { } }; + private var layoutKeyboardValues: RNILayoutKeyboardValues?; + private var layoutValueContext: RNILayoutValueContext { if let targetVC = self.targetViewController { return .init(fromTargetViewController: targetVC) ?? .default; @@ -406,6 +408,18 @@ class AdaptiveModalManager: NSObject { name: UIResponder.keyboardDidHideNotification, object: nil ); + + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardWillChange(notification:)), + name: UIResponder.keyboardWillChangeFrameNotification, + object: nil + ); + + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardDidChange(notification:)), + name: UIResponder.keyboardDidChangeFrameNotification, + object: nil + ); }; func setupViewControllers() { @@ -599,7 +613,9 @@ class AdaptiveModalManager: NSObject { UIResponder.keyboardWillShowNotification, UIResponder.keyboardDidShowNotification, UIResponder.keyboardWillHideNotification, - UIResponder.keyboardDidHideNotification + UIResponder.keyboardDidHideNotification, + UIResponder.keyboardWillChangeFrameNotification, + UIResponder.keyboardDidChangeFrameNotification, ]; notificationNames.forEach { @@ -1260,66 +1276,6 @@ class AdaptiveModalManager: NSObject { }; }; - func getKeyboardValues( - fromNotification notification: NSNotification - ) -> ( - rect: CGRect, - frameEnd: CGRect, - animationDuration: CGFloat, - animationCurve: UIView.AnimationCurve - - )? { - guard let userInfo = notification.userInfo else { return nil }; - - func extract(key: String) throws -> T { - guard let rawValue = userInfo[key], - let value = rawValue as? T - else { throw NSError() }; - - return value; - }; - - func extractValue( - userInfoKey: String, - valueKey: KeyPath - ) throws -> T { - guard let rawValue: NSValue = try? extract(key: userInfoKey) - else { throw NSError() }; - - return rawValue[keyPath: valueKey]; - }; - - do { - return ( - rect: try extractValue( - userInfoKey: UIResponder.keyboardFrameEndUserInfoKey, - valueKey: \.cgRectValue - ), - frameEnd: try extractValue( - userInfoKey: UIResponder.keyboardFrameEndUserInfoKey, - valueKey: \.cgRectValue - ), - animationDuration: try extract( - key: UIResponder.keyboardAnimationDurationUserInfoKey - ), - animationCurve: try { - let curveValue: Int = try extract( - key: UIResponder.keyboardAnimationCurveUserInfoKey - ); - - guard let curve = UIView.AnimationCurve(rawValue: curveValue) else { - throw NSError(); - }; - - return curve; - }() - ); - - } catch { - return nil; - }; - }; - func debug(prefix: String? = ""){ print( "\n - AdaptiveModalManager.debug - \(prefix ?? "N/A")" @@ -1537,45 +1493,107 @@ class AdaptiveModalManager: NSObject { }; @objc func onKeyboardWillShow(notification: NSNotification) { - guard let keyboardValues = self.getKeyboardValues(fromNotification: notification) + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; + self.layoutKeyboardValues = keyboardValues; + print( "onKeyboardWillShow", - "\n - keyboardRect:", keyboardValues.rect + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" ); }; @objc func onKeyboardDidShow(notification: NSNotification) { - guard let keyboardValues = self.getKeyboardValues(fromNotification: notification) + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; + self.layoutKeyboardValues = keyboardValues; + print( "onKeyboardDidShow", - "\n - keyboardRect:", keyboardValues.rect + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" ); }; @objc func onKeyboardWillHide(notification: NSNotification) { - guard let keyboardValues = self.getKeyboardValues(fromNotification: notification) + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; + self.layoutKeyboardValues = keyboardValues; + print( "onKeyboardWillHide", - "\n - keyboardRect:", keyboardValues.rect + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" ); }; @objc func onKeyboardDidHide(notification: NSNotification) { - guard let keyboardValues = self.getKeyboardValues(fromNotification: notification) + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; + self.layoutKeyboardValues = keyboardValues; + print( "onKeyboardDidHide", - "\n - keyboardRect:", keyboardValues.rect + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" ); }; - + + @objc func onKeyboardWillChange(notification: NSNotification) { + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) + else { return }; + + self.layoutKeyboardValues = keyboardValues; + + print( + "onKeyboardWillChange", + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" + ); + }; + + @objc func onKeyboardDidChange(notification: NSNotification) { + guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) + else { return }; + + self.layoutKeyboardValues = keyboardValues; + + print( + "onKeyboardDidChange", + "\n - frameBegin:", keyboardValues.frameBegin, + "\n - frameEnd:", keyboardValues.frameEnd, + "\n - animationDuration:", keyboardValues.animationDuration, + "\n - animationCurve:", keyboardValues.animationCurve, + "\n - notification:", notification, + "\n" + ); + }; + // MARK: - Functions - DisplayLink-Related // --------------------------------------- diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutKeyboardValues.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutKeyboardValues.swift new file mode 100644 index 00000000..2fa2c30d --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutKeyboardValues.swift @@ -0,0 +1,72 @@ +// +// RNILayoutKeyboardValues.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/21/23. +// + +import UIKit + +struct RNILayoutKeyboardValues { + var frameBegin: CGRect; + var frameEnd: CGRect; + + var animationDuration: CGFloat; + var animationCurve: UIView.AnimationCurve; +}; + +extension RNILayoutKeyboardValues { + init?(fromNotification notification: NSNotification) { + guard let userInfo = notification.userInfo else { return nil }; + + func extract(key: String) throws -> T { + guard let rawValue = userInfo[key], + let value = rawValue as? T + else { throw NSError() }; + + return value; + }; + + func extractValue( + userInfoKey: String, + valueKey: KeyPath + ) throws -> T { + + guard let rawValue: NSValue = try? extract(key: userInfoKey) + else { throw NSError() }; + + return rawValue[keyPath: valueKey]; + }; + + do { + self.frameBegin = try extractValue( + userInfoKey: UIResponder.keyboardFrameBeginUserInfoKey, + valueKey: \.cgRectValue + ); + + self.frameEnd = try extractValue( + userInfoKey: UIResponder.keyboardFrameEndUserInfoKey, + valueKey: \.cgRectValue + ); + + self.animationDuration = try extract( + key: UIResponder.keyboardAnimationDurationUserInfoKey + ); + + self.animationCurve = try { + let curveValue: Int = try extract( + key: UIResponder.keyboardAnimationCurveUserInfoKey + ); + + guard let curve = UIView.AnimationCurve(rawValue: curveValue) else { + throw NSError(); + }; + + return curve; + }(); + + } catch { + return nil; + }; + }; +}; diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj index 45ece935..81629eb6 100644 --- a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj +++ b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 886AFCAD2A3209D5004AC9FB /* RNILayoutValueMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */; }; 886AFCAF2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */; }; 886AFCB12A325B6F004AC9FB /* RNILayoutValueContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */; }; + 887AA0572A4253050089F517 /* RNILayoutKeyboardValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */; }; 88A2EF742A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A2EF732A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift */; }; 88B7D0EF29C593F400490628 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0EE29C593F400490628 /* AppDelegate.swift */; }; 88B7D0F129C593F400490628 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0F029C593F400490628 /* SceneDelegate.swift */; }; @@ -116,6 +117,7 @@ 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValueMode.swift; sourceTree = ""; }; 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValuePercentTarget.swift; sourceTree = ""; }; 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValueContext.swift; sourceTree = ""; }; + 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutKeyboardValues.swift; sourceTree = ""; }; 88A2EF732A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalConfigTestPresets.swift; sourceTree = ""; }; 88B7D0EB29C593F400490628 /* swift-programmatic-modal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "swift-programmatic-modal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 88B7D0EE29C593F400490628 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -434,6 +436,7 @@ 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */, 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */, 8849B6A62A3F7A7700A5F412 /* RNILayoutValue+StaticInit.swift */, + 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */, ); path = RNILayout; sourceTree = ""; @@ -632,6 +635,7 @@ files = ( 88D018742A1B3030004664D2 /* RNIModalFocusState.swift in Sources */, 88D0186A2A1B3030004664D2 /* RNIModalData.swift in Sources */, + 887AA0572A4253050089F517 /* RNILayoutKeyboardValues.swift in Sources */, 88D0185D2A1B3030004664D2 /* RNIIdentifiable.swift in Sources */, 88D0169E2A1B0DD3004664D2 /* RNIDraggableTestViewController.swift in Sources */, 88C2F4642A2D8D3400DA7450 /* AdaptiveModalKeyframePropertyAnimator.swift in Sources */,