diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalAnimationConfig.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalAnimationConfig.swift index 23eea98f..3ff9779f 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalAnimationConfig.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalAnimationConfig.swift @@ -23,14 +23,14 @@ struct AdaptiveModalAnimationConfig { let modalCornerRadius: CGFloat?; let modalMaskedCorners: CACornerMask?; - let modalBlurEffectStyle: UIBlurEffect.Style?; - let modalBlurEffectIntensity: CGFloat?; + let modalVisualEffect: UIVisualEffect?; + let modalVisualEffectIntensity: CGFloat?; let backgroundColor: UIColor?; let backgroundOpacity: CGFloat?; - let backgroundBlurEffectStyle: UIBlurEffect.Style?; - let backgroundBlurEffectIntensity: CGFloat?; + let backgroundVisualEffect: UIVisualEffect?; + let backgroundVisualEffectIntensity: CGFloat?; init( modalRotation: CGFloat? = nil, @@ -42,12 +42,12 @@ struct AdaptiveModalAnimationConfig { modalBackgroundOpacity: CGFloat? = nil, modalCornerRadius: CGFloat? = nil, modalMaskedCorners: CACornerMask? = nil, - modalBlurEffectStyle: UIBlurEffect.Style? = nil, - modalBlurEffectIntensity: CGFloat? = nil, + modalVisualEffect: UIVisualEffect? = nil, + modalVisualEffectIntensity: CGFloat? = nil, backgroundColor: UIColor? = nil, backgroundOpacity: CGFloat? = nil, - backgroundBlurEffectStyle: UIBlurEffect.Style? = nil, - backgroundBlurEffectIntensity: CGFloat? = nil + backgroundVisualEffect: UIVisualEffect? = nil, + backgroundVisualEffectIntensity: CGFloat? = nil ) { self.modalRotation = modalRotation; @@ -63,13 +63,13 @@ struct AdaptiveModalAnimationConfig { self.modalCornerRadius = modalCornerRadius; self.modalMaskedCorners = modalMaskedCorners; - self.modalBlurEffectStyle = modalBlurEffectStyle; - self.modalBlurEffectIntensity = modalBlurEffectIntensity; + self.modalVisualEffect = modalVisualEffect; + self.modalVisualEffectIntensity = modalVisualEffectIntensity; self.backgroundColor = backgroundColor; self.backgroundOpacity = backgroundOpacity; - self.backgroundBlurEffectStyle = backgroundBlurEffectStyle; - self.backgroundBlurEffectIntensity = backgroundBlurEffectIntensity; + self.backgroundVisualEffect = backgroundVisualEffect; + self.backgroundVisualEffectIntensity = backgroundVisualEffectIntensity; }; }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift index 03b2be46..660b7857 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift @@ -16,6 +16,8 @@ struct AdaptiveModalInterpolationPoint: Equatable { let modalCornerRadius: CGFloat; let modalMaskedCorners: CACornerMask; + + let backgroundVisualEffect: UIVisualEffect?; init( modalConfigIndex: Int, @@ -41,6 +43,9 @@ struct AdaptiveModalInterpolationPoint: Equatable { self.modalMaskedCorners = keyframePrev?.modalMaskedCorners ?? keyframePrev?.modalMaskedCorners ?? Self.DefaultMaskedCorners; + + self.backgroundVisualEffect = keyframePrev?.backgroundVisualEffect + ?? keyframePrev?.backgroundVisualEffect; }; func apply(toModalView modalView: UIView){ @@ -48,6 +53,10 @@ struct AdaptiveModalInterpolationPoint: Equatable { modalView.layer.cornerRadius = self.modalCornerRadius; modalView.layer.maskedCorners = self.modalMaskedCorners; }; + + func apply(toBackgroundEffectView effectView: UIVisualEffectView){ + effectView.effect = self.backgroundVisualEffect; + }; }; extension AdaptiveModalInterpolationPoint { diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index 8bff2cd2..982e95df 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -8,8 +8,6 @@ import UIKit - - class AdaptiveModalManager { // MARK: - Properties - Config-Related @@ -27,6 +25,7 @@ class AdaptiveModalManager { weak var targetView: UIView?; weak var modalView: UIView?; + weak var backgroundVisualEffectView: UIVisualEffectView?; var gestureOffset: CGPoint?; var gestureVelocity: CGPoint?; @@ -160,12 +159,15 @@ class AdaptiveModalManager { modalConfig: AdaptiveModalConfig, modalView: UIView, targetView: UIView, + backgroundVisualEffectView: UIVisualEffectView? = nil, currentSizeProvider: @escaping () -> CGSize ) { self.modalConfig = modalConfig; self.modalView = modalView; self.targetView = targetView; + self.backgroundVisualEffectView = backgroundVisualEffectView; + self.currentSizeProvider = currentSizeProvider; }; @@ -173,6 +175,54 @@ class AdaptiveModalManager { // MARK: - Functions - Interpolation-Related // ----------------------------------------- + func getInterpolationStepRange( + forInputValue inputValue: CGFloat + ) -> ( + rangeStart: AdaptiveModalInterpolationPoint, + rangeEnd: AdaptiveModalInterpolationPoint + )? { + guard let interpolationSteps = self.interpolationSteps, + let minStep = interpolationSteps.first, + let maxStep = interpolationSteps.last + else { return nil }; + + let lastIndex = interpolationSteps.count - 1; + + if inputValue <= minStep.computedRect.origin[keyPath: self.inputAxisKey]{ + return ( + rangeStart: minStep, + rangeEnd: interpolationSteps[1] + ); + }; + + if inputValue >= maxStep.computedRect.origin[keyPath: self.inputAxisKey]{ + return ( + rangeStart: interpolationSteps[lastIndex - 1], + rangeEnd: maxStep + ); + }; + + let firstMatch = interpolationSteps.enumerated().first { + guard let nextItem = interpolationSteps[safeIndex: $0.offset + 1] + else { return false }; + + let coordCurrent = + $0.element.computedRect.origin[keyPath: self.inputAxisKey]; + + let coordNext = + nextItem.computedRect.origin[keyPath: self.inputAxisKey]; + + return coordCurrent >= inputValue && inputValue <= coordNext; + }; + + guard let rangeStart = firstMatch?.element, + let rangeStartIndex = firstMatch?.offset, + let rangeEnd = interpolationSteps[safeIndex: rangeStartIndex + 1] + else { return nil }; + + return (rangeStart, rangeEnd); + }; + func interpolateModalRect( forInputValue inputValue: CGFloat, rangeInput: [CGFloat]? = nil, @@ -400,6 +450,10 @@ class AdaptiveModalManager { animator.addAnimations { interpolationPoint.apply(toModalView: modalView); + + if let bgEffectView = self.backgroundVisualEffectView { + interpolationPoint.apply(toBackgroundEffectView: bgEffectView); + }; }; if let completion = completion { @@ -486,54 +540,6 @@ class AdaptiveModalManager { ); }; - func getInterpolationStepRange( - forInputValue inputValue: CGFloat - ) -> ( - rangeStart: AdaptiveModalInterpolationPoint, - rangeEnd: AdaptiveModalInterpolationPoint - )? { - guard let interpolationSteps = self.interpolationSteps, - let minStep = interpolationSteps.first, - let maxStep = interpolationSteps.last - else { return nil }; - - let lastIndex = interpolationSteps.count - 1; - - if inputValue <= minStep.computedRect.origin[keyPath: self.inputAxisKey]{ - return ( - rangeStart: minStep, - rangeEnd: interpolationSteps[1] - ); - }; - - if inputValue >= maxStep.computedRect.origin[keyPath: self.inputAxisKey]{ - return ( - rangeStart: interpolationSteps[lastIndex - 1], - rangeEnd: maxStep - ); - }; - - let firstMatch = interpolationSteps.enumerated().first { - guard let nextItem = interpolationSteps[safeIndex: $0.offset + 1] - else { return false }; - - let coordCurrent = - $0.element.computedRect.origin[keyPath: self.inputAxisKey]; - - let coordNext = - nextItem.computedRect.origin[keyPath: self.inputAxisKey]; - - return coordCurrent >= inputValue && inputValue <= coordNext; - }; - - guard let rangeStart = firstMatch?.element, - let rangeStartIndex = firstMatch?.offset, - let rangeEnd = interpolationSteps[safeIndex: rangeStartIndex + 1] - else { return nil }; - - return (rangeStart, rangeEnd); - }; - // MARK: - Functions - DisplayLink-Related // --------------------------------------- diff --git a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift index ed8a758c..c6d36fc1 100644 --- a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift @@ -99,7 +99,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner - ] + ], + backgroundVisualEffect: UIBlurEffect(style: .prominent) ) ), ], @@ -121,6 +122,7 @@ class RNIDraggableTestViewController : UIViewController { modalConfig: AdaptiveModalConfigTestPresets.default.config, modalView: self.floatingView, targetView: self.view, + backgroundVisualEffectView: self.backgroundVisualEffectView, currentSizeProvider: { .zero } @@ -175,15 +177,63 @@ class RNIDraggableTestViewController : UIViewController { return view; }(); + + lazy var backgroundVisualEffectView = UIVisualEffectView(); + + lazy var dummyBackgroundView: UIView = { + let view = UIView(); + + let imageView = UIImageView( + image: UIImage(named: "DummyBackgroundImage") + ); + + imageView.contentMode = .scaleAspectFill; + + view.addSubview(imageView); + + imageView.translatesAutoresizingMaskIntoConstraints = false; + + NSLayoutConstraint.activate([ + imageView.topAnchor.constraint(equalTo: view.topAnchor), + imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]); + + return view; + }(); override func viewDidLoad() { self.view.backgroundColor = .white; + let dummyBackgroundView = self.dummyBackgroundView; + self.view.addSubview(dummyBackgroundView); + + let backgroundVisualEffectView = self.backgroundVisualEffectView; + self.view.addSubview(backgroundVisualEffectView); + + backgroundVisualEffectView.effect = nil; + let floatingView = self.floatingView; self.view.addSubview(floatingView); self.floatingViewLabel.text = "\(self.modalManager.currentSnapPointIndex)"; + dummyBackgroundView.translatesAutoresizingMaskIntoConstraints = false; + backgroundVisualEffectView.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.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), + + backgroundVisualEffectView.topAnchor.constraint(equalTo: self.view.topAnchor), + backgroundVisualEffectView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), + backgroundVisualEffectView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + backgroundVisualEffectView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), + ]); + self.modalManager.computeSnapPoints(); self.modalManager.updateModal(); }; 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 new file mode 100644 index 00000000..fb6da058 --- /dev/null +++ b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "DummyBackgroundImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} 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 new file mode 100644 index 00000000..9e293afe Binary files /dev/null and b/experiments/swift-programmatic-modal/swift-programmatic-modal/Assets.xcassets/DummyBackgroundImage.imageset/DummyBackgroundImage.png differ