From da3199d896f0bc3169dac86b20711e64b6a7ef93 Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Mon, 19 Jun 2023 07:04:33 +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 | 11 +- .../AdaptiveModal/AdaptiveModalManager.swift | 5 + .../RNILayout/RNILayout.swift | 114 +++++--- .../RNILayout/RNILayoutPreset.swift | 2 +- .../RNILayout/RNILayoutValue.swift | 2 +- .../Test/AdaptiveModalConfigTestPresets.swift | 262 +++++++++++++----- ...eModalPresentationTestViewController.swift | 2 + 7 files changed, 275 insertions(+), 123 deletions(-) diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift index 7c5fb099..88974e04 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift @@ -167,8 +167,10 @@ struct AdaptiveModalInterpolationPoint: Equatable { }; func apply(toModalBackgroundView modalBgView: UIView?){ - modalBgView?.alpha = self.modalBackgroundOpacity; - modalBgView?.backgroundColor = self.modalBackgroundColor; + guard let modalBgView = modalBgView else { return }; + + modalBgView.alpha = self.modalBackgroundOpacity; + modalBgView.backgroundColor = self.modalBackgroundColor; }; func apply(toModalBackgroundEffectView effectView: UIVisualEffectView?){ @@ -176,7 +178,10 @@ struct AdaptiveModalInterpolationPoint: Equatable { }; func apply(toBackgroundView bgView: UIView?){ - bgView?.alpha = self.backgroundOpacity; + guard let bgView = bgView else { return }; + + bgView.alpha = self.backgroundOpacity; + bgView.backgroundColor = self.backgroundColor; }; func apply(toBackgroundVisualEffectView effectView: UIView?){ diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index a9ebb2ee..81dc8dc6 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -1299,6 +1299,9 @@ class AdaptiveModalManager: NSObject { + "\n - currentInterpolationIndex: \(self.currentInterpolationIndex)" + "\n - modalView gestureRecognizers: \(self.modalView?.gestureRecognizers.debugDescription ?? "N/A")" + "\n - interpolationSteps.computedRect: \(self.interpolationSteps.map({ $0.computedRect }))" + + "\n - interpolationSteps.percent: \(self.interpolationSteps.map({ $0.percent }))" + + "\n - interpolationSteps.backgroundVisualEffectIntensity: \(self.interpolationSteps.map({ $0.backgroundVisualEffectIntensity }))" + + "\n - interpolationSteps.backgroundVisualEffect: \(self.interpolationSteps.map({ $0.backgroundVisualEffect }))" + "\n" ); }; @@ -1433,6 +1436,8 @@ class AdaptiveModalManager: NSObject { if shouldDismiss { self.notifyOnModalDidHide(); }; + + self.debug(); }; private func notifyOnModalWillHide(){ diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift index a7532a24..ccde4dad 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift @@ -26,10 +26,10 @@ public struct RNILayout { public let width : RNILayoutValue; public let height: RNILayoutValue; - public let marginLeft : RNILayoutValueMode?; - public let marginRight : RNILayoutValueMode?; - public let marginTop : RNILayoutValueMode?; - public let marginBottom: RNILayoutValueMode?; + public let marginLeft : RNILayoutValue?; + public let marginRight : RNILayoutValue?; + public let marginTop : RNILayoutValue?; + public let marginBottom: RNILayoutValue?; // MARK: - Init // ------------ @@ -41,10 +41,10 @@ public struct RNILayout { width : RNILayoutValue, height: RNILayoutValue, - marginLeft : RNILayoutValueMode? = nil, - marginRight : RNILayoutValueMode? = nil, - marginTop : RNILayoutValueMode? = nil, - marginBottom: RNILayoutValueMode? = nil + marginLeft : RNILayoutValue? = nil, + marginRight : RNILayoutValue? = nil, + marginTop : RNILayoutValue? = nil, + marginBottom: RNILayoutValue? = nil ) { self.horizontalAlignment = horizontalAlignment; self.verticalAlignment = verticalAlignment; @@ -66,10 +66,10 @@ public struct RNILayout { width : RNILayoutValue? = nil, height: RNILayoutValue? = nil, - marginLeft : RNILayoutValueMode? = nil, - marginRight : RNILayoutValueMode? = nil, - marginTop : RNILayoutValueMode? = nil, - marginBottom: RNILayoutValueMode? = nil + marginLeft : RNILayoutValue? = nil, + marginRight : RNILayoutValue? = nil, + marginTop : RNILayoutValue? = nil, + marginBottom: RNILayoutValue? = nil ) { self.horizontalAlignment = horizontalAlignment ?? prev.horizontalAlignment; self.verticalAlignment = verticalAlignment ?? prev.verticalAlignment; @@ -156,6 +156,54 @@ public struct RNILayout { return rect; }; + public func computeMargins( + usingLayoutValueContext context: RNILayoutValueContext + ) -> ( + left : CGFloat?, + right : CGFloat?, + top : CGFloat?, + bottom: CGFloat?, + + horizontal: CGFloat, + vertical : CGFloat + ) { + let computedMarginLeft = self.marginLeft?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + let computedMarginRight = self.marginRight?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + let computedMarginTop = self.marginTop?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + let computedMarginBottom = self.marginBottom?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + let computedMarginHorizontal = + (computedMarginLeft ?? 0) + (computedMarginRight ?? 0); + + let computedMarginVertical = + (computedMarginTop ?? 0) + (computedMarginBottom ?? 0); + + return ( + left : computedMarginLeft ?? 0, + right : computedMarginRight ?? 0, + top : computedMarginTop ?? 0, + bottom: computedMarginBottom ?? 0, + + horizontal: computedMarginHorizontal, + vertical : computedMarginVertical + ); + }; + // MARK: - Functions // ----------------- @@ -182,40 +230,16 @@ public struct RNILayout { var rect = self.computeRawRectOrigin(usingLayoutValueContext: context); - let computedMarginLeft = self.marginLeft?.compute( - usingLayoutValueContext: context, - preferredSizeKey: \.width - ); - - let computedMarginRight = self.marginRight?.compute( - usingLayoutValueContext: context, - preferredSizeKey: \.width - ); - - let computedMarginTop = self.marginTop?.compute( - usingLayoutValueContext: context, - preferredSizeKey: \.height - ); - - let computedMarginBottom = self.marginBottom?.compute( - usingLayoutValueContext: context, - preferredSizeKey: \.height - ); - - let computedMarginHorizontal = - (computedMarginLeft ?? 0) + (computedMarginRight ?? 0); - - let computedMarginVertical = - (computedMarginTop ?? 0) + (computedMarginBottom ?? 0); + let computedMargins = self.computeMargins(usingLayoutValueContext: context); // Margin - X-Axis switch self.horizontalAlignment { case .left: - guard let marginLeft = computedMarginLeft else { break }; + guard let marginLeft = computedMargins.left else { break }; rect.origin.x = rect.origin.x + marginLeft; case .right: - guard let marginRight = computedMarginRight else { break }; + guard let marginRight = computedMargins.right else { break }; rect.origin.x = rect.origin.x - marginRight; case .center: @@ -225,11 +249,11 @@ public struct RNILayout { // Margin - Y-Axis switch self.verticalAlignment { case .top: - guard let marginTop = computedMarginTop else { break }; + guard let marginTop = computedMargins.top else { break }; rect.origin.y = rect.origin.y + marginTop; case .bottom: - guard let marginBottom = computedMarginBottom else { break }; + guard let marginBottom = computedMargins.bottom else { break }; rect.origin.y = rect.origin.y - marginBottom; case .center: @@ -238,24 +262,24 @@ public struct RNILayout { let shouldRecomputeXAxis: Bool = { switch self.width.mode { - case .stretch: return abs(computedMarginHorizontal) < rect.width; + case .stretch: return abs(computedMargins.horizontal) < rect.width; default: return false; }; }(); let shouldRecomputeYAxis: Bool = { switch self.height.mode { - case .stretch: return abs(computedMarginVertical) < rect.height; + case .stretch: return abs(computedMargins.vertical) < rect.height; default: return false; }; }(); if shouldRecomputeXAxis { - rect.size.width = rect.size.width - computedMarginHorizontal; + rect.size.width = rect.size.width - computedMargins.horizontal; }; if shouldRecomputeYAxis { - rect.size.height = rect.size.height - computedMarginVertical; + rect.size.height = rect.size.height - computedMargins.vertical; }; if shouldRecomputeXAxis || shouldRecomputeYAxis { diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift index ef68098b..2d2e5245 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift @@ -79,7 +79,7 @@ enum RNILayoutPreset { marginLeft: .constant(0), marginRight: .percent( relativeTo: .currentWidth, - percentValue: 1 + percentValue: -1 ) ); diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift index 9ea6d799..3f920dbd 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift @@ -78,7 +78,7 @@ public struct RNILayoutValue { preferredSizeKey: nil ); - let computedMaxValue = self.minValue?.compute( + let computedMaxValue = self.maxValue?.compute( usingLayoutValueContext: context, preferredSizeKey: nil ); diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift index ff2e85ec..2c60563d 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift @@ -25,6 +25,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { case demo03; case demo04; case demo05; + case demo06; + case demo07; var config: AdaptiveModalConfig { switch self { @@ -177,12 +179,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .percent(percentValue: 0.8) - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.2) - ) + width: .percent(percentValue: 0.8), + height: .percent(percentValue: 0.2) ), animationKeyframe: AdaptiveModalAnimationConfig( modalBorderWidth: 2, @@ -199,12 +197,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .percent(percentValue: 0.8) - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.4) - ) + width: .percent(percentValue: 0.8), + height: .percent(percentValue: 0.4) ), animationKeyframe: AdaptiveModalAnimationConfig( modalBorderWidth: 4, @@ -220,12 +214,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .percent(percentValue: 0.9) - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.7) - ) + width: .percent(percentValue: 0.9), + height: .percent(percentValue: 0.7) ), animationKeyframe: AdaptiveModalAnimationConfig( modalBorderWidth: 8, @@ -250,12 +240,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .left, verticalAlignment: .center, - width: RNILayoutValue( - mode: .percent(percentValue: 0.5) - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.65) - ), + width: .percent(percentValue: 0.5), + height: .percent(percentValue: 0.65), marginLeft: .constant(15) ), animationKeyframe: AdaptiveModalAnimationConfig( @@ -266,12 +252,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .center, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.85) - ), + width: .stretch, + height: .percent(percentValue: 0.85), marginLeft: .constant(20), marginRight: .constant(20) ), @@ -306,43 +288,30 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoints: [ AdaptiveModalSnapPointConfig( snapPoint: RNILayout( - horizontalAlignment: .center, - verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.1) - ) + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .stretch, + height: .percent(percentValue: 0.1) ) ), AdaptiveModalSnapPointConfig( snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.3) - ) + width: .stretch, + height: .percent(percentValue: 0.3) ) ), AdaptiveModalSnapPointConfig( snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.7) - ) + width: .stretch, + height: .percent(percentValue: 0.7) ) ), ], snapDirection: .bottomToTop - //snapPercentStrategy: .index ); case .test02: return AdaptiveModalConfig( @@ -351,12 +320,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.3) - ) + width: .stretch, + height: .percent(percentValue: 0.3) ), animationKeyframe: AdaptiveModalAnimationConfig( modalCornerRadius: 15, @@ -412,12 +377,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.3) - ) + width: .stretch, + height: .percent(percentValue: 0.3) ), animationKeyframe: AdaptiveModalAnimationConfig( //modalOpacity: 1, @@ -443,19 +404,16 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNILayoutValue( - mode: .stretch - ), - height: RNILayoutValue( - mode: .percent(percentValue: 0.5) - ), + width: .stretch, + height: .percent(percentValue: 0.5), marginLeft: .constant(15), marginRight: .constant(15), - marginBottom: .constant(15) + marginBottom: .init( + mode: .safeAreaInsets(insetKey: \.bottom), + minValue: .constant(15) + ) ), animationKeyframe: AdaptiveModalAnimationConfig( - //modalOpacity: 0.5, - //modalBackgroundColor: .red, modalShadowOffset: .init(width: 2, height: 2), modalShadowOpacity: 0.2, modalShadowRadius: 15, @@ -468,7 +426,6 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { ], modalBackgroundOpacity: 0.85, modalBackgroundVisualEffectIntensity: 0.6, - //backgroundColor: .red, backgroundOpacity: 0.1, backgroundVisualEffectIntensity: 0.075 ) @@ -819,6 +776,165 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { layoutPreset: .edgeRight ) ); + + case .demo06: return AdaptiveModalConfig( + snapPoints: [ + // snap point - 1 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .percent(percentValue: 0.8), + height: .percent(percentValue: 0.2), + marginBottom: .init( + mode: .safeAreaInsets(insetKey: \.bottom), + minValue: .constant(15) + ) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 0, height: -2), + modalShadowOpacity: 0.3, + modalShadowRadius: 7, + modalCornerRadius: 10, + backgroundOpacity: 0, + backgroundVisualEffect: UIBlurEffect(style: .regular), + backgroundVisualEffectIntensity: 0 + ) + ), + + // snap point - 2 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .percent(percentValue: 0.85), + height: .percent(percentValue: 0.4), + marginBottom: .init( + mode: .safeAreaInsets(insetKey: \.bottom), + minValue: .constant(15) + ) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 1, height: 1), + modalShadowOpacity: 0.4, + modalShadowRadius: 7, + modalCornerRadius: 15, + backgroundOpacity: 0.1 + ) + ), + + // snap point - 3 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .percent(percentValue: 0.87), + height: .percent(percentValue: 0.7), + marginBottom: .init( + mode: .safeAreaInsets(insetKey: \.bottom), + minValue: .constant(15) + ) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 2, height: 2), + modalShadowOpacity: 0.3, + modalShadowRadius: 8, + backgroundOpacity: 0.3, + backgroundVisualEffectIntensity: 0.3 + ) + ), + ], + snapDirection: .bottomToTop, + overshootSnapPoint: AdaptiveModalSnapPointPreset( + layoutPreset: .layoutConfig( + .init( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .percent(percentValue: 0.87), + height: .stretch, + marginTop: .init( + mode: .safeAreaInsets(insetKey: \.top), + minValue: .constant(15) + ), + marginBottom: .init( + mode: .safeAreaInsets(insetKey: \.bottom), + minValue: .constant(15) + ) + ) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 3, height: 3), + modalShadowOpacity: 0.35, + modalShadowRadius: 15 + ) + ) + ); + + case .demo07: return AdaptiveModalConfig( + snapPoints: [ + // snap point - 1 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .percent(percentValue: 0.7), + height: .percent(percentValue: 0.65), + marginLeft: .constant(15) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalScaleX: 1, + modalScaleY: 1, + modalShadowOffset: .init(width: 1, height: 1), + modalShadowOpacity: 0.3, + modalShadowRadius: 10, + modalCornerRadius: 15, + modalBackgroundOpacity: 0.85, + modalBackgroundVisualEffectIntensity: 0.9, + backgroundColor: .black, + backgroundOpacity: 0.15, + backgroundVisualEffectIntensity: 0.05 + ) + ), + + // snap point - 2 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .percent(percentValue: 0.9), + height: .percent(percentValue: 0.85) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .zero, + modalShadowOpacity: 0, + modalShadowRadius: 0, + modalBackgroundOpacity: 0, + modalBackgroundVisualEffectOpacity: 0, + modalBackgroundVisualEffectIntensity: 0, + backgroundColor: .white, + backgroundOpacity: 0.5, + backgroundVisualEffectIntensity: 1 + ) + ), + ], + snapDirection: .leftToRight, + undershootSnapPoint: .init( + layoutPreset: .offscreenLeft, + animationKeyframe: .init( + modalScaleX: 0.5, + modalScaleY: 0.5, + modalCornerRadius: 10, + modalBackgroundOpacity: 1, + modalBackgroundVisualEffect: UIBlurEffect(style: .regular), + modalBackgroundVisualEffectIntensity: 0, + backgroundVisualEffect: UIBlurEffect(style: .regular), + backgroundVisualEffectIntensity: 0 + ) + ), + overshootSnapPoint: AdaptiveModalSnapPointPreset( + layoutPreset: .edgeRight + ) + ); }; }; }; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index 125c51bb..77a144dd 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -97,6 +97,8 @@ class AdaptiveModalPresentationTestViewController : UIViewController { .demo03, .demo04, .demo05, + .demo06, + .demo07, ]; var currentModalConfigPresetCounter = 0;