diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift index 382224db..e5b7585e 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift @@ -33,9 +33,12 @@ struct AdaptiveModalConfig { let snapAnimationConfig: AdaptiveModalSnapAnimationConfig; let interpolationClampingConfig: AdaptiveModalClampingConfig; + // rename to undershootSnapPoint let initialSnapPoint: AdaptiveModalSnapPointPreset; let overshootSnapPoint: AdaptiveModalSnapPointPreset; + let initialSnapPointIndex: Int; + // let entranceConfig: AdaptiveModalEntranceConfig; // let snapSwipeVelocityThreshold: CGFloat = 0; @@ -102,6 +105,7 @@ struct AdaptiveModalConfig { snapPercentStrategy: SnapPercentStrategy = .position, snapAnimationConfig: AdaptiveModalSnapAnimationConfig = .default, interpolationClampingConfig: AdaptiveModalClampingConfig = .default, + initialSnapPointIndex: Int = 1, initialSnapPoint: AdaptiveModalSnapPointPreset? = nil, overshootSnapPoint: AdaptiveModalSnapPointPreset? = nil ) { @@ -113,6 +117,8 @@ struct AdaptiveModalConfig { self.snapAnimationConfig = snapAnimationConfig; self.interpolationClampingConfig = interpolationClampingConfig; + self.initialSnapPointIndex = initialSnapPointIndex; + self.initialSnapPoint = initialSnapPoint ?? .getDefaultInitialSnapPoint(forDirection: snapDirection); diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift index b689c435..e4567305 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift @@ -19,6 +19,32 @@ extension AdaptiveModalManager: UIViewControllerAnimatedTransitioning { func animateTransition( using transitionContext: UIViewControllerContextTransitioning ) { - //TBA + guard let fromViewController = transitionContext.viewController(forKey: .from), + let toViewController = transitionContext.view(forKey: .to) + else { return }; + + self.targetView = transitionContext.containerView; + + self.currentInterpolationIndex = 1; + + self.computeSnapPoints(); + + self.setupInitViews(); + self.setupDummyModalView(); + self.setupGestureHandler(); + + self.setupAddViews(); + self.setupViewConstraints(); + + self.updateModal(); + + print( + "transitionContext" + + "\n - containerView: \(transitionContext.containerView)" + + "\n - modalView: + \(self.modalView)" + + "\n - targetView: + \(self.targetView)" + + "\n - currentInterpolationIndex: + \(self.currentInterpolationIndex)" + + "\n - currentInterpolationStep: + \(self.currentInterpolationStep)" + ); }; }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift index 42cd0f6a..6f30c4a5 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift @@ -8,6 +8,7 @@ import UIKit + extension AdaptiveModalManager: UIViewControllerTransitioningDelegate { func animationController( @@ -30,10 +31,13 @@ extension AdaptiveModalManager: UIViewControllerTransitioningDelegate { source: UIViewController ) -> UIPresentationController? { - return AdaptiveModalPresentationController( + let presentationController = AdaptiveModalPresentationController( presentedViewController: presented, presenting: presenting, modalManager: self ); + + //presentationController.delegate = self; + return presentationController; }; }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index 9940cab2..0fa94d8c 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -7,7 +7,7 @@ import UIKit -class AdaptiveModalManager: NSObject { +class AdaptiveModalManager: NSObject, UIGestureRecognizerDelegate { // MARK: - Properties - Config-Related // ------------------------------------ @@ -73,7 +73,7 @@ class AdaptiveModalManager: NSObject { var prevInterpolationIndex = 0; var nextInterpolationIndex: Int?; - var currentInterpolationIndex = 1 { + var currentInterpolationIndex = 0 { didSet { self.prevInterpolationIndex = oldValue; } @@ -216,38 +216,12 @@ class AdaptiveModalManager: NSObject { // MARK: - Init // ------------ - init( - modalConfig: AdaptiveModalConfig, - modalView: UIView, - targetView: UIView, - currentSizeProvider: (() -> CGSize)? = nil - ) { - self.modalConfig = modalConfig; - - self.modalView = modalView; - self.targetView = targetView; - - super.init(); - - self.computeSnapPoints(); - - self.setupInitViews(); - self.setupDummyModalView(); - self.setupGestureHandler(); - - self.setupAddViews(); - self.setupViewConstraints(); - }; - init(modalConfig: AdaptiveModalConfig) { self.modalConfig = modalConfig; super.init(); self.computeSnapPoints(); - self.setupViewControllers(); - self.setupInitViews(); - self.setupDummyModalView(); }; deinit { @@ -257,31 +231,15 @@ class AdaptiveModalManager: NSObject { // MARK: - Functions - Setup // ------------------------- - func setupViewControllers() { - modalViewController?.modalPresentationStyle = .custom; - modalViewController?.transitioningDelegate = self; - }; - func setupInitViews(){ - self.modalBackgroundView = UIView(); - self.modalBackgroundVisualEffectView = UIVisualEffectView(); + //self.modalBackgroundView = UIView(); + //self.modalBackgroundVisualEffectView = UIVisualEffectView(); self.backgroundDimmingView = UIView(); self.backgroundVisualEffectView = UIVisualEffectView(); }; - func setupGestureHandler(){ - guard let modalView = self.modalView else { return }; - - modalView.addGestureRecognizer( - UIPanGestureRecognizer( - target: self, - action: #selector(self.onDragPanGesture(_:)) - ) - ); - }; - - private func setupDummyModalView(){ + func setupDummyModalView(){ guard let targetView = self.targetView else { return }; let dummyModalView = self.dummyModalView; @@ -292,7 +250,7 @@ class AdaptiveModalManager: NSObject { targetView.addSubview(dummyModalView); }; - private func setupAddViews(){ + func setupAddViews(){ guard let modalView = self.modalView, let targetView = self.targetView else { return }; @@ -317,6 +275,7 @@ class AdaptiveModalManager: NSObject { modalView.clipsToBounds = true; modalView.backgroundColor = .clear; + modalWrapperView.addSubview(modalView); if let modalBackgroundView = self.modalBackgroundView { @@ -332,7 +291,6 @@ class AdaptiveModalManager: NSObject { modalView.sendSubviewToBack(modalBGVisualEffectView); modalBGVisualEffectView.clipsToBounds = true; - modalBGVisualEffectView.backgroundColor = .clear; modalBGVisualEffectView.isUserInteractionEnabled = false; }; }; @@ -395,6 +353,29 @@ class AdaptiveModalManager: NSObject { ]); }; }; + + func setupGestureHandler(){ + guard let modalView = self.modalView else { return }; + + let gesture = UIPanGestureRecognizer( + target: self, + action: #selector(Self.onDragPanGesture(_:)) + ); + + gesture.isEnabled = true; + gesture.minimumNumberOfTouches = 1; + gesture.maximumNumberOfTouches = 1; + gesture.delegate = self; + + modalView.addGestureRecognizer(gesture); + modalView.isUserInteractionEnabled = true; + modalView.backgroundColor = .systemBackground; + }; + + func setupViewControllers() { + modalViewController?.modalPresentationStyle = .custom; + modalViewController?.transitioningDelegate = self; + }; // MARK: - Functions - Interpolation-Related Helpers // ------------------------------------------------- @@ -1042,6 +1023,13 @@ class AdaptiveModalManager: NSObject { return nextIndex; }; + public func gestureRecognizer( + _ gestureRecognizer: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer + ) -> Bool { + return true; + }; + @objc func onDragPanGesture(_ sender: UIPanGestureRecognizer) { let gesturePoint = sender.location(in: self.targetView); self.gesturePoint = gesturePoint; @@ -1143,27 +1131,37 @@ class AdaptiveModalManager: NSObject { // MARK: - User-Invoked Functions // ------------------------------ - - func set( - viewControllerToPresent: UIViewController, - presentingViewController: UIViewController + + func prepareForPresentation( + modalView: UIView, + targetView: UIView ) { - self.modalViewController = viewControllerToPresent; - self.targetViewController = presentingViewController; + self.modalView = modalView; + self.targetView = targetView; - self.modalView = viewControllerToPresent.view; - self.targetView = presentingViewController.view; + modalView.isUserInteractionEnabled = true; - self.setupViewControllers(); - self.setupDummyModalView(); self.setupInitViews(); - self.setupGestureHandler(); + self.setupDummyModalView(); self.setupAddViews(); self.setupViewConstraints(); + self.setupGestureHandler(); self.computeSnapPoints(); self.updateModal(); + + modalView.frame = self.modalWrapperView.frame; + }; + + func showModal( + completion: ((UIViewAnimatingPosition) -> Void)? = nil + ){ + self.currentInterpolationIndex = self.modalConfig.initialSnapPointIndex; + self.animateModal( + to: self.currentInterpolationStep, + completion: completion + ); }; func computeSnapPoints( @@ -1190,6 +1188,10 @@ class AdaptiveModalManager: NSObject { }; }; + func snapToCurrentIndex(){ + self.animateModal(to: self.currentInterpolationStep); + }; + func snapToClosestSnapPoint( forPoint point: CGPoint, duration: CGFloat? = nil, diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift index 72ed4a5b..e28dc29c 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift @@ -22,5 +22,13 @@ class AdaptiveModalPresentationController: UIPresentationController { ); self.modalManager = modalManager; - } + }; + + override func presentationTransitionWillBegin() { + + }; + + override func presentationTransitionDidEnd(_ completed: Bool) { + + }; }; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index 2fce756d..a8602c4d 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -68,13 +68,13 @@ class AdaptiveModalPresentationTestViewController : UIViewController { }; @objc func onPressButtonPresentViewController(_ sender: UIButton) { + let testVC = TestViewController(); - self.adaptiveModalManager.set( - viewControllerToPresent: testVC, - presentingViewController: self - ); - + let manager = self.adaptiveModalManager; + manager.modalViewController = testVC; + manager.modalView = testVC.view; + manager.setupViewControllers(); self.present(testVC, animated: true); }; diff --git a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift index ab6dfdf9..1bb7ed6b 100644 --- a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift @@ -325,19 +325,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { class RNIDraggableTestViewController : UIViewController { - lazy var modalManager = { - let manager = AdaptiveModalManager( - modalConfig: AdaptiveModalConfigTestPresets.default.config, - modalView: self.floatingView, - targetView: self.view, - currentSizeProvider: { - .zero - } - ); - - manager.eventDelegate = self; - return manager; - }(); + var modalManager: AdaptiveModalManager?; private var initialGesturePoint: CGPoint = .zero; private var floatingViewInitialCenter: CGPoint = .zero @@ -345,17 +333,10 @@ class RNIDraggableTestViewController : UIViewController { lazy var floatingViewLabel: UILabel = { let label = UILabel(); - // label.text = "\(self.modalManager.currentSnapPointIndex)"; + label.text = "\(self.modalManager?.currentSnapPointIndex ?? -1)"; label.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.5); label.font = .boldSystemFont(ofSize: 22); - - label.addGestureRecognizer( - UITapGestureRecognizer( - target: self, - action: #selector(self.onPressFloatingViewLabel(_:)) - ) - ); - + return label; }(); @@ -388,13 +369,7 @@ class RNIDraggableTestViewController : UIViewController { return view; }(); - - lazy var modalBackgroundView = UIView(); - lazy var modalBackgroundVisualEffectView = UIVisualEffectView(); - - lazy var backgroundDimmingView = UIView(); - lazy var backgroundVisualEffectView = UIVisualEffectView(); - + lazy var dummyBackgroundView: UIView = { let view = UIView(); @@ -417,43 +392,76 @@ class RNIDraggableTestViewController : UIViewController { return view; }(); - + override func viewDidLoad() { self.view.backgroundColor = .white; - let dummyBackgroundView = self.dummyBackgroundView; - self.view.addSubview(dummyBackgroundView); - - self.floatingViewLabel.text = "\(self.modalManager.currentSnapPointIndex)"; + let dummyBackgroundView: UIView = { + let imageView = UIImageView( + image: UIImage(named: "DummyBackgroundImage") + ); + + imageView.contentMode = .scaleAspectFill; + return imageView; + }(); + self.view.addSubview(dummyBackgroundView); dummyBackgroundView.translatesAutoresizingMaskIntoConstraints = false; - + NSLayoutConstraint.activate([ - dummyBackgroundView.topAnchor.constraint(equalTo: self.view.topAnchor), - dummyBackgroundView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), - dummyBackgroundView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + dummyBackgroundView.topAnchor .constraint(equalTo: self.view.topAnchor ), + dummyBackgroundView.bottomAnchor .constraint(equalTo: self.view.bottomAnchor ), + dummyBackgroundView.leadingAnchor .constraint(equalTo: self.view.leadingAnchor ), dummyBackgroundView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), ]); - // self.modalManager.setupAddViews(); - // self.modalManager.setupViewConstraints(); - }; - - override func viewDidLayoutSubviews() { - self.modalManager.computeSnapPoints(); - self.modalManager.updateModal(); + let presentButton: UIButton = { + let button = UIButton(); + + button.setTitle("Show Modal", for: .normal); + button.configuration = .filled(); + + button.addTarget( + self, + action: #selector(self.onPressButtonPresentViewController(_:)), + for: .touchUpInside + ); + + return button; + }(); + + self.view.addSubview(presentButton); + presentButton.translatesAutoresizingMaskIntoConstraints = false; + + NSLayoutConstraint.activate([ + presentButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), + presentButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor) + ]); }; - @objc func onPressFloatingViewLabel(_ sender: UITapGestureRecognizer){ - // self.layoutConfigCount += 1; - // self.updateFloatingView(isAnimated: true); + @objc func onPressButtonPresentViewController(_ sender: UIButton){ + let manager = AdaptiveModalManager( + modalConfig: AdaptiveModalConfigTestPresets.default.config + ); + + manager.prepareForPresentation( + modalView: self.floatingView, + targetView: self.view + ); + + manager.showModal(){ _ in + manager.setupGestureHandler(); + } + + print( + "onPressButtonPresentViewController" + + "\n - floatingView.superview: \(self.floatingView.superview)" + + "\n - floatingView: \(self.floatingView)" + + "\n - manager.modalWrapperView: \(manager.modalWrapperView)" + + "\n - manager.modalWrapperView.subviews: \(manager.modalWrapperView.subviews)" + + "\n - manager.modalWrapperView.subviews.first!.subviews: \(manager.modalWrapperView.subviews.first!.subviews)" + ); }; - - // @objc func onDragPanGestureView(_ sender: UIPanGestureRecognizer) { - // // print("onDragPanGestureView - velocity: \(sender.velocity(in: self.view))"); - // - // self.modalManager.notifyOnDragPanGesture(sender); - // }; }; extension RNIDraggableTestViewController: AdaptiveModalEventNotifiable { diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/Contents.json b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/Contents.json index fb6da058..1bdb1f53 100644 --- a/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/Contents.json +++ b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "DummyBackgroundImage.png", + "filename" : "iphone.jpg", "idiom" : "universal", "scale" : "1x" }, diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/DummyBackgroundImage.png b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/DummyBackgroundImage.png deleted file mode 100644 index 9e293afe..00000000 Binary files a/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/DummyBackgroundImage.png and /dev/null differ diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/iphone.jpg b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/iphone.jpg new file mode 100644 index 00000000..349a3834 Binary files /dev/null and b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/iphone.jpg differ