From 367880c66edc23c41d3dc02adbf643ad0df60d41 Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Wed, 21 Jun 2023 00:14:06 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=AB=20Update:=20Exp=20-=20`AdaptiveMod?= =?UTF-8?q?al`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Update experiment/test - `swift-programmatic-modal/AdaptiveModal`. --- .../AdaptiveModal/AdaptiveModalManager.swift | 239 ++++++++++++------ .../Test/AdaptiveModalConfigTestPresets.swift | 34 +++ ...eModalPresentationTestViewController.swift | 26 +- 3 files changed, 227 insertions(+), 72 deletions(-) diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index e18bca86..de90b73a 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -372,15 +372,43 @@ class AdaptiveModalManager: NSObject { super.init(); self.computeSnapPoints(); + self.setupObservers(); }; deinit { self.clearAnimators(); + self.removeObservers(); }; // MARK: - Functions - Setup // ------------------------- + private func setupObservers(){ + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardWillShow(notification:)), + name: UIResponder.keyboardWillShowNotification, + object: nil + ); + + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardDidShow(notification:)), + name: UIResponder.keyboardDidShowNotification, + object: nil + ); + + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardWillHide(notification:)), + name: UIResponder.keyboardWillHideNotification, + object: nil + ); + + NotificationCenter.default.addObserver(self, + selector: #selector(self.onKeyboardDidHide(notification:)), + name: UIResponder.keyboardDidHideNotification, + object: nil + ); + }; + func setupViewControllers() { guard let modalVC = self.modalViewController else { return }; @@ -545,6 +573,90 @@ class AdaptiveModalManager: NSObject { ]); }; }; + + // MARK: - Functions - Cleanup-Related + // ----------------------------------- + + private func clearGestureValues() { + self.gestureOffset = nil; + self.gestureInitialPoint = nil; + self.gestureVelocity = nil; + self.gesturePoint = nil; + }; + + private func clearAnimators() { + self.backgroundVisualEffectAnimator?.clear(); + self.backgroundVisualEffectAnimator = nil; + + self.modalBackgroundVisualEffectAnimator?.clear(); + self.modalBackgroundVisualEffectAnimator = nil; + + self.modalAnimator?.stopAnimation(true); + self.modalAnimator = nil; + }; + + private func removeObservers(){ + let notificationNames = [ + UIResponder.keyboardWillShowNotification, + UIResponder.keyboardDidShowNotification, + UIResponder.keyboardWillHideNotification, + UIResponder.keyboardDidHideNotification + ]; + + notificationNames.forEach { + NotificationCenter.default.removeObserver(self, name: $0, object: nil); + }; + }; + + private func cleanupViews() { + let viewsToCleanup: [UIView?] = [ + self.dummyModalView, + self.modalWrapperView, + // self.modalWrapperTransformView, + // self.nodalView, + self.modalWrapperShadowView, + self.modalBackgroundView, + self.modalBackgroundVisualEffectView, + self.backgroundDimmingView, + self.backgroundVisualEffectView + ]; + + viewsToCleanup.forEach { + guard let view = $0 else { return }; + + view.removeAllAncestorConstraints(); + view.removeFromSuperview(); + }; + + self.modalView = nil; + self.targetView = nil; + + self.modalBackgroundView = nil; + self.modalBackgroundVisualEffectView = nil; + self.backgroundDimmingView = nil; + self.backgroundVisualEffectView = nil; + + self.didTriggerSetup = false; + }; + + private func cleanupSnapPointOverride(){ + self.isOverridingSnapPoints = false; + self.overrideSnapPoints = nil; + self.overrideInterpolationPoints = nil; + + self.prevOverrideInterpolationIndex = 0; + self.nextOverrideInterpolationIndex = nil; + self.currentOverrideInterpolationIndex = 0; + }; + + private func cleanup() { + self.clearGestureValues(); + self.clearAnimators(); + self.cleanupViews(); + self.cleanupSnapPointOverride(); + + self.currentInterpolationIndex = 0; + }; // MARK: - Functions - Interpolation-Related Helpers // ------------------------------------------------- @@ -1104,77 +1216,6 @@ class AdaptiveModalManager: NSObject { self.applyInterpolationToModal(forPoint: gesturePointWithOffset); }; - // MARK: - Functions - Cleanup-Related - // ----------------------------------- - - private func clearGestureValues() { - self.gestureOffset = nil; - self.gestureInitialPoint = nil; - self.gestureVelocity = nil; - self.gesturePoint = nil; - }; - - private func clearAnimators() { - self.backgroundVisualEffectAnimator?.clear(); - self.backgroundVisualEffectAnimator = nil; - - self.modalBackgroundVisualEffectAnimator?.clear(); - self.modalBackgroundVisualEffectAnimator = nil; - - self.modalAnimator?.stopAnimation(true); - self.modalAnimator = nil; - }; - - private func cleanupViews() { - let viewsToCleanup: [UIView?] = [ - self.dummyModalView, - self.modalWrapperView, - // self.modalWrapperTransformView, - // self.nodalView, - self.modalWrapperShadowView, - self.modalBackgroundView, - self.modalBackgroundVisualEffectView, - self.backgroundDimmingView, - self.backgroundVisualEffectView - ]; - - viewsToCleanup.forEach { - guard let view = $0 else { return }; - - view.removeAllAncestorConstraints(); - view.removeFromSuperview(); - }; - - self.modalView = nil; - self.targetView = nil; - - self.modalBackgroundView = nil; - self.modalBackgroundVisualEffectView = nil; - self.backgroundDimmingView = nil; - self.backgroundVisualEffectView = nil; - - self.didTriggerSetup = false; - }; - - private func cleanupSnapPointOverride(){ - self.isOverridingSnapPoints = false; - self.overrideSnapPoints = nil; - self.overrideInterpolationPoints = nil; - - self.prevOverrideInterpolationIndex = 0; - self.nextOverrideInterpolationIndex = nil; - self.currentOverrideInterpolationIndex = 0; - }; - - private func cleanup() { - self.clearGestureValues(); - self.clearAnimators(); - self.cleanupViews(); - self.cleanupSnapPointOverride(); - - self.currentInterpolationIndex = 0; - }; - // MARK: - Functions - Helpers/Utilities // ------------------------------------- @@ -1216,6 +1257,18 @@ class AdaptiveModalManager: NSObject { }; }; + private func getKeyboardRect( + fromNotification notification: NSNotification + ) -> CGRect? { + + guard let userInfo = notification.userInfo, + let keyboardFrameRaw = userInfo[UIResponder.keyboardFrameEndUserInfoKey], + let keyboardFrame = keyboardFrameRaw as? NSValue + else { return nil }; + + return keyboardFrame.cgRectValue; + }; + func debug(prefix: String? = ""){ print( "\n - AdaptiveModalManager.debug - \(prefix ?? "N/A")" @@ -1391,6 +1444,9 @@ class AdaptiveModalManager: NSObject { self.startDisplayLink(); }; + // MARK: - Functions - Handlers + // ---------------------------- + @objc private func onDragPanGesture(_ sender: UIPanGestureRecognizer) { let gesturePoint = sender.location(in: self.targetView); self.gesturePoint = gesturePoint; @@ -1429,6 +1485,47 @@ class AdaptiveModalManager: NSObject { }; }; + @objc func onKeyboardWillShow(notification: NSNotification) { + guard let keyboardRect = self.getKeyboardRect(fromNotification: notification) + else { return }; + + print( + "onKeyboardWillShow", + "\n - keyboardRect:", keyboardRect + ); + }; + + @objc func onKeyboardDidShow(notification: NSNotification) { + guard let keyboardRect = self.getKeyboardRect(fromNotification: notification) + else { return }; + + print( + "onKeyboardDidShow", + "\n - keyboardRect:", keyboardRect + ); + }; + + + @objc func onKeyboardWillHide(notification: NSNotification) { + guard let keyboardRect = self.getKeyboardRect(fromNotification: notification) + else { return }; + + print( + "onKeyboardWillHide", + "\n - keyboardRect:", keyboardRect + ); + }; + + @objc func onKeyboardDidHide(notification: NSNotification) { + guard let keyboardRect = self.getKeyboardRect(fromNotification: notification) + else { return }; + + print( + "onKeyboardDidHide", + "\n - keyboardRect:", keyboardRect + ); + }; + // MARK: - Functions - DisplayLink-Related // --------------------------------------- diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift index b986322e..9294b484 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift @@ -28,6 +28,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { case demo06; case demo07; case demo08; + case demo09; var config: AdaptiveModalConfig { switch self { @@ -993,6 +994,39 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { layoutPreset: .fitScreen ) ); + + case .demo09: return AdaptiveModalConfig( + snapPoints: [ + // Snap Point 1 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .stretch, + height: .percent(percentValue: 0.3) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 0, height: -2), + modalShadowOpacity: 0.2, + modalShadowRadius: 7, + modalCornerRadius: 0, + modalMaskedCorners: [ + .layerMinXMinYCorner, + .layerMaxXMinYCorner + ], + modalBackgroundOpacity: 0.9, + modalBackgroundVisualEffect: UIBlurEffect(style: .systemUltraThinMaterial), + modalBackgroundVisualEffectIntensity: 1, + backgroundVisualEffect: UIBlurEffect(style: .regular), + backgroundVisualEffectIntensity: 0 + ) + ), + ], + snapDirection: .bottomToTop, + overshootSnapPoint: AdaptiveModalSnapPointPreset( + layoutPreset: .fitScreen + ) + ); }; }; }; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index 593b98b0..09b57a31 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -13,6 +13,7 @@ fileprivate class TestModalViewController: UIViewController, AdaptiveModalEventN var showDismissButton = true; var showCustomSnapPointButton = false; + var showTextInputField = false; lazy var floatingViewLabel: UILabel = { let label = UILabel(); @@ -57,6 +58,21 @@ fileprivate class TestModalViewController: UIViewController, AdaptiveModalEventN return button; }(); + let textInputField: UITextField = { + let textField = UITextField(); + + textField.placeholder = "Enter text here"; + textField.font = UIFont.systemFont(ofSize: 15); + textField.borderStyle = UITextField.BorderStyle.roundedRect; + textField.autocorrectionType = UITextAutocorrectionType.no; + textField.keyboardType = UIKeyboardType.default; + textField.returnKeyType = UIReturnKeyType.done; + textField.clearButtonMode = UITextField.ViewMode.whileEditing; + textField.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center; + + return textField; + }(); + let stackView: UIStackView = { let stack = UIStackView(); @@ -67,6 +83,10 @@ fileprivate class TestModalViewController: UIViewController, AdaptiveModalEventN stack.addArrangedSubview(self.floatingViewLabel); + if self.showTextInputField { + stack.addArrangedSubview(textInputField); + }; + if self.showDismissButton { stack.addArrangedSubview(dismissButton); }; @@ -163,6 +183,7 @@ class AdaptiveModalPresentationTestViewController : UIViewController { .demo06, .demo07, .demo08, + .demo09, ]; var currentModalConfigPresetCounter = 0; @@ -296,8 +317,11 @@ class AdaptiveModalPresentationTestViewController : UIViewController { let testVC = TestModalViewController(); switch self.currentModalConfigPreset { - case .demo08, .demo07: + case .demo07, .demo08: testVC.showCustomSnapPointButton = true; + + case .demo09: + testVC.showTextInputField = true; default: break; };