From a3d5f4abd47cf98fdfb7f56524e3a52d7b2f7137 Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Sun, 4 Jun 2023 17:27:12 +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`. --- .../AdaptiveModalInterpolationPoint.swift | 28 +++-- .../AdaptiveModal/AdaptiveModalManager.swift | 101 +++++++++++++----- .../Test/RNIDraggableTestViewController.swift | 8 +- 3 files changed, 101 insertions(+), 36 deletions(-) diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift index c42bb2f5..009ec40c 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift @@ -15,15 +15,15 @@ struct AdaptiveModalInterpolationPoint: Equatable { /// The computed frames of the modal based on the snap points let computedRect: CGRect; - //let modalRotation: CGFloat?; + //let modalRotation: CGFloat; - //let modalScaleX: CGFloat?; - //let modalScaleY: CGFloat?; + //let modalScaleX: CGFloat; + //let modalScaleY: CGFloat; - //let modalTranslateX: CGFloat?; - //let modalTranslateY: CGFloat?; + //let modalTranslateX: CGFloat; + //let modalTranslateY: CGFloat; - //let modalBackgroundColor: UIColor?; + //let modalBackgroundColor: UIColor; let modalBackgroundOpacity: CGFloat; let modalCornerRadius: CGFloat; @@ -32,8 +32,8 @@ struct AdaptiveModalInterpolationPoint: Equatable { let modalBackgroundVisualEffect: UIVisualEffect?; let modalBackgroundVisualEffectIntensity: CGFloat; - //let backgroundColor: UIColor?; - //let backgroundOpacity: CGFloat?; + //let backgroundColor: UIColor; + let backgroundOpacity: CGFloat; let backgroundVisualEffect: UIVisualEffect?; let backgroundVisualEffectIntensity: CGFloat; @@ -100,6 +100,10 @@ struct AdaptiveModalInterpolationPoint: Equatable { ?? keyframePrev?.modalBackgroundVisualEffectIntensity ?? 1; + self.backgroundOpacity = keyframeCurrent?.backgroundOpacity + ?? keyframePrev?.backgroundOpacity + ?? 0; + self.backgroundVisualEffect = keyframeCurrent?.backgroundVisualEffect ?? keyframePrev?.backgroundVisualEffect; @@ -114,13 +118,17 @@ struct AdaptiveModalInterpolationPoint: Equatable { modalView.layer.maskedCorners = self.modalMaskedCorners; }; - func apply(toModalBackgroundView modalBackgroundView: UIView?){ - modalBackgroundView?.alpha = self.modalBackgroundOpacity; + func apply(toModalBackgroundView modalBgView: UIView?){ + modalBgView?.alpha = self.modalBackgroundOpacity; }; func apply(toBackgroundEffectView effectView: UIVisualEffectView?){ effectView?.effect = self.backgroundVisualEffect; }; + + func apply(toBackgroundView bgView: UIView?){ + bgView?.alpha = self.backgroundOpacity; + }; }; extension AdaptiveModalInterpolationPoint { diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index 3eaec5f1..0d5bd7d6 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -28,6 +28,7 @@ class AdaptiveModalManager { weak var modalBackgroundView: UIView?; weak var modalBackgroundVisualEffectView: UIVisualEffectView?; + weak var backgroundDimmingView: UIView?; weak var backgroundVisualEffectView: UIVisualEffectView?; var displayLinkStartTimestamp: CFTimeInterval?; @@ -179,6 +180,7 @@ class AdaptiveModalManager { targetView: UIView, modalBackgroundView: UIView? = nil, modalBackgroundVisualEffectView: UIVisualEffectView? = nil, + backgroundDimmingView: UIView? = nil, backgroundVisualEffectView: UIVisualEffectView? = nil, currentSizeProvider: @escaping () -> CGSize ) { @@ -188,13 +190,12 @@ class AdaptiveModalManager { self.targetView = targetView; self.modalBackgroundView = modalBackgroundView; - self.backgroundVisualEffectView = backgroundVisualEffectView; self.modalBackgroundVisualEffectView = modalBackgroundVisualEffectView; - self.currentSizeProvider = currentSizeProvider; + self.backgroundVisualEffectView = backgroundVisualEffectView; + self.backgroundDimmingView = backgroundDimmingView; - modalBackgroundView?.backgroundColor = .systemBackground; - modalView.backgroundColor = .clear; + self.currentSizeProvider = currentSizeProvider; }; deinit { @@ -216,6 +217,14 @@ class AdaptiveModalManager { bgVisualEffectView.backgroundColor = .clear; }; + if let bgDimmingView = self.backgroundDimmingView { + targetView.addSubview(bgDimmingView); + + bgDimmingView.clipsToBounds = true; + bgDimmingView.backgroundColor = .black; + bgDimmingView.alpha = 0; + }; + targetView.addSubview(modalView); modalView.clipsToBounds = true; @@ -226,6 +235,7 @@ class AdaptiveModalManager { modalView.sendSubviewToBack(modalBackgroundView); modalBackgroundView.backgroundColor = .systemBackground; + modalBackgroundView.isUserInteractionEnabled = false; }; if let modalBGVisualEffectView = self.modalBackgroundVisualEffectView { @@ -234,6 +244,7 @@ class AdaptiveModalManager { modalBGVisualEffectView.clipsToBounds = true; modalBGVisualEffectView.backgroundColor = .clear; + modalBGVisualEffectView.isUserInteractionEnabled = false; }; }; @@ -253,6 +264,17 @@ class AdaptiveModalManager { ]); }; + if let bgDimmingView = self.backgroundDimmingView { + bgDimmingView.translatesAutoresizingMaskIntoConstraints = false; + + NSLayoutConstraint.activate([ + bgDimmingView.topAnchor .constraint(equalTo: targetView.topAnchor ), + bgDimmingView.bottomAnchor .constraint(equalTo: targetView.bottomAnchor ), + bgDimmingView.leadingAnchor .constraint(equalTo: targetView.leadingAnchor ), + bgDimmingView.trailingAnchor.constraint(equalTo: targetView.trailingAnchor), + ]); + }; + if let modalBGView = self.modalBackgroundView { modalBGView.translatesAutoresizingMaskIntoConstraints = false; @@ -438,8 +460,27 @@ class AdaptiveModalManager { guard let modalCornerRadius = modalCornerRadius else { return nil }; return modalCornerRadius; }; + + func interpolateBackgroundOpacity( + forInputPercentValue inputPercentValue: CGFloat, + rangeInput: [CGFloat]? = nil, + rangeOutput: [AdaptiveModalInterpolationPoint]? = nil + ) -> CGFloat? { + + guard let interpolationSteps = rangeOutput ?? self.interpolationStepsSorted, + let interpolationRangeInput = rangeInput ?? self.interpolationRangeInput + else { return nil }; - func applyInterpolationToBackgroundVisualEffect( + return Self.interpolate( + inputValue: inputPercentValue, + rangeInput: interpolationRangeInput, + rangeOutput: interpolationSteps.map { + $0.backgroundOpacity + } + ); + }; + + func applyInterpolationToModalBackgroundVisualEffect( forInputPercentValue inputPercentValue: CGFloat ) { @@ -449,20 +490,20 @@ class AdaptiveModalManager { ); guard let interpolationRange = interpolationRange else { return nil }; - let animator = self.backgroundVisualEffectAnimator; + let animator = self.modalBackgroundVisualEffectAnimator; - let animatorDidRangeChange = animator?.didRangeChange( + let animatorRangeDidChange = animator?.didRangeChange( interpolationRangeStart: interpolationRange.rangeStart, interpolationRangeEnd: interpolationRange.rangeEnd ); - if let animator = animator, !animatorDidRangeChange! { + if let animator = animator, !animatorRangeDidChange! { return animator; }; animator?.clear(); - guard let visualEffectView = self.backgroundVisualEffectView + guard let visualEffectView = self.modalBackgroundVisualEffectView else { return nil }; visualEffectView.effect = nil; @@ -471,19 +512,19 @@ class AdaptiveModalManager { interpolationRangeStart: interpolationRange.rangeStart, interpolationRangeEnd: interpolationRange.rangeEnd, forComponent: visualEffectView, - interpolationOutputKey: \.backgroundVisualEffectIntensity + interpolationOutputKey: \.modalBackgroundVisualEffectIntensity ) { - $0.effect = $1.backgroundVisualEffect; + $0.effect = $1.modalBackgroundVisualEffect; }; }(); guard let animator = animator else { return }; - self.backgroundVisualEffectAnimator = animator; + self.modalBackgroundVisualEffectAnimator = animator; animator.setFractionComplete(forInputPercentValue: inputPercentValue); }; - - func applyInterpolationToModalBackgroundVisualEffect( + + func applyInterpolationToBackgroundVisualEffect( forInputPercentValue inputPercentValue: CGFloat ) { @@ -493,20 +534,20 @@ class AdaptiveModalManager { ); guard let interpolationRange = interpolationRange else { return nil }; - let animator = self.modalBackgroundVisualEffectAnimator; + let animator = self.backgroundVisualEffectAnimator; - let animatorRangeDidChange = animator?.didRangeChange( + let animatorDidRangeChange = animator?.didRangeChange( interpolationRangeStart: interpolationRange.rangeStart, interpolationRangeEnd: interpolationRange.rangeEnd ); - if let animator = animator, !animatorRangeDidChange! { + if let animator = animator, !animatorDidRangeChange! { return animator; }; animator?.clear(); - guard let visualEffectView = self.modalBackgroundVisualEffectView + guard let visualEffectView = self.backgroundVisualEffectView else { return nil }; visualEffectView.effect = nil; @@ -515,14 +556,14 @@ class AdaptiveModalManager { interpolationRangeStart: interpolationRange.rangeStart, interpolationRangeEnd: interpolationRange.rangeEnd, forComponent: visualEffectView, - interpolationOutputKey: \.modalBackgroundVisualEffectIntensity + interpolationOutputKey: \.backgroundVisualEffectIntensity ) { - $0.effect = $1.modalBackgroundVisualEffect; + $0.effect = $1.backgroundVisualEffect; }; }(); guard let animator = animator else { return }; - self.modalBackgroundVisualEffectAnimator = animator; + self.backgroundVisualEffectAnimator = animator; animator.setFractionComplete(forInputPercentValue: inputPercentValue); }; @@ -545,12 +586,20 @@ class AdaptiveModalManager { modalView.layer.cornerRadius = nextModalRadius; }; - if let nextModalBackgroundOpacity = self.interpolateModalBackgroundOpacity( + if let modalBgView = self.modalBackgroundView, + let nextModalBgOpacity = self.interpolateModalBackgroundOpacity( forInputPercentValue: inputPercentValue - ), - let modalBackgroundView = self.modalBackgroundView { + ) { - modalBackgroundView.alpha = nextModalBackgroundOpacity; + modalBgView.alpha = nextModalBgOpacity; + }; + + if let bgDimmingView = self.backgroundDimmingView, + let nextBgOpacity = self.interpolateBackgroundOpacity( + forInputPercentValue: inputPercentValue + ) { + + bgDimmingView.alpha = nextBgOpacity; }; self.applyInterpolationToBackgroundVisualEffect( @@ -670,7 +719,9 @@ class AdaptiveModalManager { animator.addAnimations { interpolationPoint.apply(toModalView: modalView); + interpolationPoint.apply(toModalBackgroundView: self.modalBackgroundView); + interpolationPoint.apply(toBackgroundView: self.backgroundDimmingView); }; if let completion = completion { diff --git a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift index 856154bb..6e1705a6 100644 --- a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift @@ -140,6 +140,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { ], modalBackgroundVisualEffect: UIBlurEffect(style: .systemUltraThinMaterial), modalBackgroundVisualEffectIntensity: 1, + backgroundOpacity: 0, backgroundVisualEffect: UIBlurEffect(style: .systemUltraThinMaterialDark), backgroundVisualEffectIntensity: 0 ) @@ -169,6 +170,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { .layerMaxXMaxYCorner ], modalBackgroundVisualEffectIntensity: 0.6, + backgroundOpacity: 0.1, backgroundVisualEffectIntensity: 0.075 ) ), @@ -196,6 +198,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { .layerMaxXMaxYCorner ], modalBackgroundVisualEffectIntensity: 1, + backgroundOpacity: 0, backgroundVisualEffectIntensity: 0.5 ) ), @@ -246,6 +249,7 @@ class RNIDraggableTestViewController : UIViewController { targetView: self.view, modalBackgroundView: self.modalBackgroundView, modalBackgroundVisualEffectView: self.modalBackgroundVisualEffectView, + backgroundDimmingView: self.backgroundDimmingView, backgroundVisualEffectView: self.backgroundVisualEffectView, currentSizeProvider: { .zero @@ -303,9 +307,11 @@ class RNIDraggableTestViewController : UIViewController { }(); lazy var modalBackgroundView = UIView(); - lazy var backgroundVisualEffectView = UIVisualEffectView(); lazy var modalBackgroundVisualEffectView = UIVisualEffectView(); + lazy var backgroundDimmingView = UIView(); + lazy var backgroundVisualEffectView = UIVisualEffectView(); + lazy var dummyBackgroundView: UIView = { let view = UIView();