From f4f8d061f89b39b5b76b8ea9b222294be1e425ee Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Thu, 22 Jun 2023 04:43:39 +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 | 66 ++- .../RNILayout/RNILayout.swift | 240 +++++--- .../RNILayout/RNILayoutMarginRects.swift | 52 ++ .../RNILayout/RNILayoutMargins.swift | 71 +++ .../RNILayout/RNILayoutPreset.swift | 12 +- .../RNILayout/RNILayoutValueMode.swift | 2 +- .../Test/AdaptiveModalConfigTestPresets.swift | 4 +- ...eModalPresentationTestViewController.swift | 3 +- .../Test/RNILayoutTestViewController.swift | 515 +++++++++++++++++- .../project.pbxproj | 8 + 10 files changed, 868 insertions(+), 105 deletions(-) create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutMarginRects.swift create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutMargins.swift diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index 6d50f7b8..ffdcb67d 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -126,6 +126,10 @@ public class AdaptiveModalManager: NSObject { var overrideSnapPoints: [AdaptiveModalSnapPointConfig]?; var overrideInterpolationPoints: [AdaptiveModalInterpolationPoint]?; + var currentOverrideInterpolationStep: AdaptiveModalInterpolationPoint? { + self.overrideInterpolationPoints?[self.currentOverrideInterpolationIndex]; + }; + private var shouldUseOverrideSnapPoints: Bool { self.isOverridingSnapPoints && self.overrideSnapPoints != nil @@ -133,8 +137,9 @@ public class AdaptiveModalManager: NSObject { }; private var shouldClearOverrideSnapPoints: Bool { - self.shouldUseOverrideSnapPoints && - self.currentOverrideInterpolationIndex < overrideInterpolationPoints!.count - 2; + self.shouldUseOverrideSnapPoints + && self.currentOverrideInterpolationIndex < overrideInterpolationPoints!.count - 2 + && self.presentationState != .dismissing }; // MARK: - Properties - Interpolation Points @@ -174,12 +179,12 @@ public class AdaptiveModalManager: NSObject { public private(set) var currentInterpolationIndex: Int { get { - self.shouldSnapToOvershootSnapPoint + self.shouldUseOverrideSnapPoints ? self.currentOverrideInterpolationIndex : self.currentConfigInterpolationIndex; } set { - if self.shouldSnapToOvershootSnapPoint { + if self.shouldUseOverrideSnapPoints { self.currentOverrideInterpolationIndex = newValue; } else { @@ -1303,8 +1308,20 @@ public class AdaptiveModalManager: NSObject { + "\n - modalViewController: \(self.modalViewController?.debugDescription ?? "N/A")" + "\n - targetViewController: \(self.targetViewController?.debugDescription ?? "N/A")" + "\n - currentInterpolationIndex: \(self.currentInterpolationIndex)" + + "\n - currentOverrideInterpolationIndex: \(self.currentOverrideInterpolationIndex)" + + "\n - currentConfigInterpolationIndex: \(self.currentConfigInterpolationIndex)" + + "\n - currentInterpolationStep: computedRect \(self.currentInterpolationStep.computedRect)" + + "\n - currentConfigInterpolationStep computedRect: \(self.currentConfigInterpolationStep.computedRect)" + + "\n - currentOverrideInterpolationStep computedRect: \(self.currentOverrideInterpolationStep?.computedRect.debugDescription ?? "N/A")" + "\n - modalView gestureRecognizers: \(self.modalView?.gestureRecognizers.debugDescription ?? "N/A")" + + "\n - isOverridingSnapPoints: \(self.isOverridingSnapPoints)" + + "\n - shouldUseOverrideSnapPoints: \(self.shouldUseOverrideSnapPoints)" + + "\n - shouldClearOverrideSnapPoints: \(self.shouldClearOverrideSnapPoints)" + + "\n - layoutKeyboardValues: \(self.layoutKeyboardValues.debugDescription )" + + "\n - presentationState: \(self.presentationState )" + "\n - interpolationSteps.computedRect: \(self.interpolationSteps.map({ $0.computedRect }))" + + "\n - configInterpolationSteps.computedRect: \(self.configInterpolationSteps.map({ $0.computedRect }))" + + "\n - overrideInterpolationPoints.computedRect: \((self.overrideInterpolationPoints ?? []).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 }))" @@ -1364,7 +1381,6 @@ public class AdaptiveModalManager: NSObject { let closestInterpolationIndex = closestSnapPoint.offset; let interpolationPoint = interpolationSteps[closestInterpolationIndex]; - let snapPointIndex = interpolationPoint.snapPointIndex; return ( interpolationIndex: closestInterpolationIndex, @@ -1511,8 +1527,12 @@ public class AdaptiveModalManager: NSObject { guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; - self.layoutKeyboardValues = keyboardValues; - self.computeSnapPoints(); + if self.presentationState != .dismissing { + self.layoutKeyboardValues = keyboardValues; + self.computeSnapPoints(); + }; + + self.animateModal( to: self.currentInterpolationStep, @@ -1551,9 +1571,13 @@ public class AdaptiveModalManager: NSObject { guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; + self.debug(prefix: "onKeyboardWillHide - pre"); + self.clearLayoutKeyboardValues(); self.computeSnapPoints(); + + self.animateModal( to: self.currentInterpolationStep, animator: keyboardValues.keyboardAnimator @@ -1591,8 +1615,10 @@ public class AdaptiveModalManager: NSObject { guard let keyboardValues = RNILayoutKeyboardValues(fromNotification: notification) else { return }; - self.layoutKeyboardValues = keyboardValues; - self.computeSnapPoints(); + if self.presentationState == .dismissing { + self.layoutKeyboardValues = keyboardValues; + self.computeSnapPoints(); + }; print( "onKeyboardWillChange", @@ -1690,6 +1716,8 @@ public class AdaptiveModalManager: NSObject { let interpolationSteps = self.interpolationSteps!; let prevIndex = self.currentInterpolationIndex; + self.debug(prefix: "notifyOnModalWillSnap"); + let nextIndexRaw: Int = { guard let nextIndex = self.nextInterpolationIndex else { let closestSnapPoint = self.getClosestSnapPoint(); @@ -1736,6 +1764,8 @@ public class AdaptiveModalManager: NSObject { if self.shouldClearOverrideSnapPoints { self.cleanupSnapPointOverride(); }; + + //self.debug(prefix: "notifyOnModalDidSnap") self.eventDelegate?.notifyOnModalDidSnap( prevSnapPointIndex: @@ -1855,10 +1885,14 @@ public class AdaptiveModalManager: NSObject { let nextIndex = 0; + self.debug(prefix: "hideModal"); + if useInBetweenSnapPoints { self.snapTo(interpolationIndex: nextIndex, completion: completion); } else { + self.computeSnapPoints(); + let currentSnapPointConfig = self.currentSnapPointConfig; let currentInterpolationStep = self.currentInterpolationStep; @@ -2049,6 +2083,8 @@ public class AdaptiveModalManager: NSObject { interpolationPoints.append(nextInterpolationPoint); + let nextInterpolationPointIndex = interpolationPoints.count - 1; + let overshootSnapPoint = AdaptiveModalInterpolationPoint( usingModalConfig: self.modalConfig, snapPointIndex: interpolationPoints.count, @@ -2062,8 +2098,20 @@ public class AdaptiveModalManager: NSObject { self.isOverridingSnapPoints = true; self.overrideSnapPoints = snapPoints; self.overrideInterpolationPoints = interpolationPoints; + self.currentOverrideInterpolationIndex = nextInterpolationPointIndex; + + print( + "snapTo", + "\n - prevInterpolationPoints:", prevInterpolationPoints.count, + "\n - interpolationPoints:", interpolationPoints.count, + "\n - nextInterpolationPointIndex:", nextInterpolationPointIndex + ); + + self.debug(prefix: "snapTo"); + self.animateModal(to: nextInterpolationPoint, completion: { _ in + self.debug(prefix: "snapTo - completion"); completion?(); }); }; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift index ccde4dad..e112ea70 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift @@ -8,6 +8,9 @@ import UIKit public struct RNILayout { + + // MARK: - Public Types + // -------------------- public enum HorizontalAlignment: String { case left, right, center; @@ -156,54 +159,6 @@ 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 // ----------------- @@ -230,58 +185,175 @@ public struct RNILayout { var rect = self.computeRawRectOrigin(usingLayoutValueContext: context); - let computedMargins = self.computeMargins(usingLayoutValueContext: context); - - // Margin - X-Axis - switch self.horizontalAlignment { - case .left: - guard let marginLeft = computedMargins.left else { break }; - rect.origin.x = rect.origin.x + marginLeft; + let computedMargins = RNILayoutMargins( + usingLayoutConfig: self, + usingLayoutValueContext: context + ); + + let marginRects = RNILayoutMarginRects( + margins: computedMargins, + viewRect: rect, + targetRect: context.targetRect + ); + + let shouldResizeWidth: Bool = { + if computedMargins.horizontal == 0 { + return false; + }; + + if self.width.mode == .stretch && + !computedMargins.hasNegativeHorizontalMargins { + + return true; + }; + + return ( + computedMargins.left > 0 + && computedMargins.right > 0 + && computedMargins.horizontal > rect.width + ); + }(); + + let shouldResizeHeight: Bool = { + if computedMargins.vertical == 0 { + return false; + }; + + if self.height.mode == .stretch && + !computedMargins.hasNegativeVerticalMargins { + + return true; + }; + + return ( + computedMargins.top > 0 + && computedMargins.bottom > 0 + && computedMargins.vertical > rect.height + ); + }(); + + if shouldResizeWidth { + let offsetWidth = self.width.mode == .stretch + ? computedMargins.horizontal + : computedMargins.horizontal - rect.width; + + rect.size.width -= offsetWidth; + }; + + if shouldResizeHeight { + let offsetHeight = self.height.mode == .stretch + ? computedMargins.vertical + : computedMargins.vertical - rect.height; + + rect.size.height -= offsetHeight; + }; + + let shouldOffsetX: Bool = { + switch self.horizontalAlignment { + case .left, .right: + return true; + + case .center: + return + marginRects.left.maxX > rect.minX || + marginRects.right.minX < rect.maxX; + }; + }(); + + let shouldOffsetY: Bool = { + switch self.verticalAlignment { + case .top, .bottom: + return true; + + case .center: + return + marginRects.top.maxY > rect.minY || + marginRects.bottom.minY < rect.maxY; + }; + }(); + + if shouldOffsetX { + let offsetLeft = computedMargins.left - rect.minX; + + let shouldApplyNegativeLeftMargin = + self.horizontalAlignment == .left && + computedMargins.left < 0; + + if offsetLeft > 0 { + rect.origin.x += offsetLeft; + + } else if shouldApplyNegativeLeftMargin { + rect.origin.x -= abs(computedMargins.left); + }; + + let offsetRight: CGFloat = { + let marginRightX = context.targetRect.maxX - computedMargins.right; + return rect.maxX - marginRightX; + }(); + + let shouldApplyNegativeRightMargin = + self.horizontalAlignment == .right && + computedMargins.right < 0; - case .right: - guard let marginRight = computedMargins.right else { break }; - rect.origin.x = rect.origin.x - marginRight; + if offsetRight > 0 { + rect.origin.x -= offsetRight; - case .center: - break; + } else if shouldApplyNegativeRightMargin { + rect.origin.x += abs(computedMargins.right); + }; }; - // Margin - Y-Axis - switch self.verticalAlignment { - case .top: - guard let marginTop = computedMargins.top else { break }; - rect.origin.y = rect.origin.y + marginTop; + if shouldOffsetY { + let offsetTop = computedMargins.top - rect.minY; + + let shouldApplyNegativeTopMargin = + self.verticalAlignment == .top && + computedMargins.top < 0; + + if offsetTop > 0 { + rect.origin.y += offsetTop; - case .bottom: - guard let marginBottom = computedMargins.bottom else { break }; - rect.origin.y = rect.origin.y - marginBottom; + } else if shouldApplyNegativeTopMargin { + rect.origin.y -= abs(computedMargins.top); + }; + + let offsetBottom: CGFloat = { + let marginBottomY = context.targetRect.maxY - computedMargins.bottom; + return rect.maxY - marginBottomY; + }(); + + let shouldApplyNegativeBottomMargin = + self.verticalAlignment == .bottom && + computedMargins.bottom < 0; - case .center: - break; + if offsetBottom > 0 { + rect.origin.y -= offsetBottom; + + } else if shouldApplyNegativeBottomMargin { + rect.origin.y += abs(computedMargins.bottom); + }; }; let shouldRecomputeXAxis: Bool = { - switch self.width.mode { - case .stretch: return abs(computedMargins.horizontal) < rect.width; - default: return false; + switch self.horizontalAlignment { + case .center: + return !shouldOffsetX && shouldResizeWidth + + default: + return false; }; }(); let shouldRecomputeYAxis: Bool = { - switch self.height.mode { - case .stretch: return abs(computedMargins.vertical) < rect.height; - default: return false; + switch self.verticalAlignment { + case .center: + return !shouldOffsetY && shouldResizeHeight + + default: + return false; }; }(); - if shouldRecomputeXAxis { - rect.size.width = rect.size.width - computedMargins.horizontal; - }; - - if shouldRecomputeYAxis { - rect.size.height = rect.size.height - computedMargins.vertical; - }; - if shouldRecomputeXAxis || shouldRecomputeYAxis { // re-compute origin rect = self.computeRawRectOrigin( diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutMarginRects.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutMarginRects.swift new file mode 100644 index 00000000..2b93060c --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutMarginRects.swift @@ -0,0 +1,52 @@ +// +// RNILayoutMarginRects.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/22/23. +// + +import Foundation + +public struct RNILayoutMarginRects { + + var left : CGRect; + var right : CGRect; + var top : CGRect; + var bottom: CGRect; + + init( + margins: RNILayoutMargins, + viewRect: CGRect, + targetRect: CGRect + ) { + self.left = CGRect( + origin: .zero, + size: CGSize( + width: margins.left, + height: targetRect.height + ) + ); + + self.right = CGRect( + x: targetRect.maxX - margins.right, + y: 0, + width: margins.right, + height: targetRect.height + ); + + self.top = CGRect( + origin: .zero, + size: CGSize( + width: targetRect.width, + height: margins.top + ) + ); + + self.bottom = CGRect( + x: 0, + y: targetRect.maxY - margins.bottom, + width: targetRect.width, + height: margins.bottom + ); + }; +}; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutMargins.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutMargins.swift new file mode 100644 index 00000000..a8b62ad9 --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutMargins.swift @@ -0,0 +1,71 @@ +// +// RNILayoutMargin.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/22/23. +// + +import Foundation + +public struct RNILayoutMargins { + public var left : CGFloat; + public var right : CGFloat; + public var top : CGFloat; + public var bottom: CGFloat; + + public var horizontal: CGFloat { + self.left + self.right; + }; + + public var vertical: CGFloat { + self.top + self.bottom; + }; + + public var hasNegativeHorizontalMargins: Bool { + self.left < 0 || self.right < 0; + }; + + public var hasNegativeVerticalMargins: Bool { + self.top < 0 || self.bottom < 0; + }; + + init( + left: CGFloat? = nil, + right: CGFloat? = nil, + top: CGFloat? = nil, + bottom: CGFloat? = nil + ) { + self.left = left ?? 0; + self.right = right ?? 0; + self.top = top ?? 0; + self.bottom = bottom ?? 0; + } +}; + +public extension RNILayoutMargins { + + init( + usingLayoutConfig layoutConfig: RNILayout, + usingLayoutValueContext context: RNILayoutValueContext + ) { + self.left = layoutConfig.marginLeft?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ) ?? 0; + + self.right = layoutConfig.marginRight?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ) ?? 0; + + self.top = layoutConfig.marginTop?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ) ?? 0; + + self.bottom = layoutConfig.marginBottom?.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ) ?? 0; + }; +}; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift index cc66e46a..82b97ba6 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift @@ -136,19 +136,22 @@ public enum RNILayoutPreset { case .edgeTop: return .init( derivedFrom: baseLayoutConfig, - verticalAlignment: .top + verticalAlignment: .top, + marginTop: .constant(0) ); case .edgeLeft: return .init( derivedFrom: baseLayoutConfig, - horizontalAlignment: .left + horizontalAlignment: .left, + marginLeft: .constant(0) ); case .edgeRight: return .init( derivedFrom: baseLayoutConfig, - horizontalAlignment: .right + horizontalAlignment: .right, + marginRight: .constant(0) ); case .center: @@ -190,8 +193,7 @@ public enum RNILayoutPreset { height: RNILayoutValue( mode: .stretch ), - marginTop: .constant(0), - marginBottom: .constant(0) + marginTop: .constant(0) ); case let .layoutConfig(config): diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift index 234d1cc9..5d0af3fb 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift @@ -7,7 +7,7 @@ import UIKit -public enum RNILayoutValueMode { +public enum RNILayoutValueMode: Equatable { case stretch; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift index a9048a4d..62fe69b8 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift @@ -652,7 +652,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { ) ), overshootSnapPoint: AdaptiveModalSnapPointPreset( - layoutPreset: .edgeRight + layoutPreset: .offscreenRight ) ); @@ -1035,7 +1035,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { ], snapDirection: .bottomToTop, overshootSnapPoint: AdaptiveModalSnapPointPreset( - layoutPreset: .fitScreen + layoutPreset: .fitScreenVertically ) ); diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index c2c32c85..9019ad9b 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -127,6 +127,7 @@ fileprivate class TestModalViewController: UIViewController, AdaptiveModalEventN ]), marginBottom: .multipleValues([ .safeAreaInsets(insetKey: \.bottom), + .keyboardRelativeSize(sizeKey: \.height), .constant(15), ]) ), @@ -322,7 +323,7 @@ class AdaptiveModalPresentationTestViewController : UIViewController { testVC.showCustomSnapPointButton = true; case .demo09: - //testVC.showCustomSnapPointButton = true; + testVC.showCustomSnapPointButton = true; testVC.showTextInputField = true; case .demo10: diff --git a/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift index af1ec03e..2bd84af4 100644 --- a/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift @@ -19,9 +19,7 @@ enum ScreenSize { }; }; -class RNILayoutTestViewController : UIViewController { - - lazy var layoutConfigs: [RNILayout] = [ +let oldLayoutConfigs: [RNILayout] = [ // 0 A RNILayout( horizontalAlignment: .left, @@ -308,6 +306,517 @@ class RNILayoutTestViewController : UIViewController { ), ]; +let boxSizeSmall: CGFloat = 125; + + +class RNILayoutTestViewController : UIViewController { + + lazy var layoutConfigs: [RNILayout] = [ + + // MARK: Corners Test + // ------------------ + + // 0 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125) + ), + + // 1 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125) + ), + + // 2 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125) + ), + + // 3 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: .constant(125), + height: .constant(125) + ), + + // 4 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125) + ), + + // 5 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125) + ), + + // 6 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125) + ), + + // 7 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .constant(125), + height: .constant(125) + ), + + // MARK: Corners + Safe Area Margin Test + // ------------------------------------- + + // 8 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125), + marginLeft: .safeAreaInsets( + insetKey: \.left, + minValue: .constant(10) + ), + marginTop: .safeAreaInsets( + insetKey: \.top, + minValue: .constant(10) + ) + ), + + // 9 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125), + marginTop: .safeAreaInsets( + insetKey: \.top, + minValue: .constant(10) + ) + ), + + // 10 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .top, + width: .constant(125), + height: .constant(125), + marginRight: .safeAreaInsets( + insetKey: \.right, + minValue: .constant(10) + ), + marginTop: .safeAreaInsets( + insetKey: \.top, + minValue: .constant(10) + ) + ), + + // 11 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: .constant(125), + height: .constant(125), + marginRight: .safeAreaInsets( + insetKey: \.right, + minValue: .constant(10) + ) + ), + + // 12 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125), + marginRight: .safeAreaInsets( + insetKey: \.right, + minValue: .constant(10) + ), + marginBottom: .safeAreaInsets( + insetKey: \.bottom, + minValue: .constant(10) + ) + ), + + // 13 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125), + marginBottom: .safeAreaInsets( + insetKey: \.bottom, + minValue: .constant(10) + ) + ), + + // 14 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .bottom, + width: .constant(125), + height: .constant(125), + marginLeft: .safeAreaInsets( + insetKey: \.left, + minValue: .constant(10) + ), + marginBottom: .safeAreaInsets( + insetKey: \.bottom, + minValue: .constant(10) + ) + ), + + // 15 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .constant(125), + height: .constant(125), + marginLeft: .safeAreaInsets( + insetKey: \.left, + minValue: .constant(10) + ) + ), + + // MARK: Vertical Stretch Test + // --------------------------- + + // 16 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch, + marginLeft: .percent( + relativeTo: .currentWidth, + percentValue: -0.5 + ) + ), + + // 17 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch + ), + + // 18 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch + ), + + // 19 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch + ), + + // 20 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch, + marginRight: .percent( + relativeTo: .currentWidth, + percentValue: -0.5 + ) + ), + + // MARK: Vertical Stretch Test + Margin `multipleValues` + // ---------------------------------------------------- + + // 21 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch, + marginLeft: .multipleValues([ + .safeAreaInsets(insetKey: \.left), + .constant(15), + ]), + marginTop: .multipleValues([ + .safeAreaInsets(insetKey: \.top), + .constant(15), + ]), + marginBottom: .multipleValues([ + .safeAreaInsets(insetKey: \.bottom), + .constant(15), + ]) + ), + + // 22 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch, + marginTop: .multipleValues([ + .safeAreaInsets(insetKey: \.top), + .constant(15), + ]), + marginBottom: .multipleValues([ + .safeAreaInsets(insetKey: \.bottom), + .constant(15), + ]) + ), + + // 23 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: .percent(percentValue: 0.5), + height: .stretch, + marginRight: .multipleValues([ + .safeAreaInsets(insetKey: \.right), + .constant(15), + ]), + marginTop: .multipleValues([ + .safeAreaInsets(insetKey: \.top), + .constant(15), + ]), + marginBottom: .multipleValues([ + .safeAreaInsets(insetKey: \.bottom), + .constant(15), + ]) + ), + + // MARK: Horizontal Stretch Test + // ----------------------------- + + // 24 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .stretch, + height: .percent(percentValue: 0.4), + marginBottom: .percent( + relativeTo: .currentHeight, + percentValue: -0.5 + ) + ), + + // 25 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .stretch, + height: .percent(percentValue: 0.4) + ), + + // 26 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .stretch, + height: .percent(percentValue: 0.4) + ), + + // 27 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .top, + width: .stretch, + height: .percent(percentValue: 0.4) + ), + + // 28 + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .top, + width: .stretch, + height: .percent(percentValue: 0.4), + marginTop: .percent( + relativeTo: .currentHeight, + percentValue: -0.5 + ) + ), + + // MARK: Horizontal/Vertical Center Test + // ------------------------------------- + + // 29 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .constant(150), + height: .constant(150), + marginBottom: .constant(100) + ), + + // MARK: Misc + // ---------- + + // 6 G + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.3) + ) + ), + // 7 H + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .top, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.3) + ) + ), + // 8 I + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: RNILayoutValue( + mode: .percent(percentValue: 0.7), + maxValue: .constant(ScreenSize.iPhone8.size.width) + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.7), + maxValue: .constant(ScreenSize.iPhone8.size.height) + ) + ), + // 9 J + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .top, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.3) + ), + marginLeft: .constant(20), + marginRight: .constant(20) + ), + // 10 K + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.3) + ), + marginLeft: .constant(20), + marginRight: .constant(20) + ), + // 11 L + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: RNILayoutValue( + mode: .percent(percentValue: 0.5) + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.6), + maxValue: .constant(ScreenSize.iPhone8.size.height) + ) + ), + // 12 M + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: RNILayoutValue( + mode: .percent(percentValue: 0.5) + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.6), + maxValue: .constant(ScreenSize.iPhone8.size.height) + ) + ), + // N + // O = 13 + RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: RNILayoutValue( + mode: .percent(percentValue: 0.4) + ), + height: RNILayoutValue( + mode: .stretch, + maxValue: .constant(ScreenSize.iPhone8.size.height) + ), + marginLeft: .constant(20), + marginTop: .constant(20), + marginBottom: .constant(20) + ), + // P + RNILayout( + horizontalAlignment: .right, + verticalAlignment: .center, + width: RNILayoutValue( + mode: .percent(percentValue: 0.4) + ), + height: RNILayoutValue( + mode: .stretch, + maxValue: .constant(ScreenSize.iPhone8.size.height) + ), + marginRight: .constant(20), + marginTop: .constant(20), + marginBottom: .constant(20) + ), + // Q = 15 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.4) + ), + marginLeft: .constant(20), + marginRight: .constant(20), + marginBottom: .constant(15) + ), + // R - 16 + RNILayout( + horizontalAlignment: .center, + verticalAlignment: .top, + width: RNILayoutValue( + mode: .stretch + ), + height: RNILayoutValue( + mode: .percent(percentValue: 0.4) + ), + marginLeft: .constant(20), + marginRight: .constant(20), + marginTop: .constant(20) + ) + ]; + var layoutConfigCount = 0; var layoutConfigIndex: Int { diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj index ea3a6dea..670b2a98 100644 --- a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj +++ b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 886AFCB12A325B6F004AC9FB /* RNILayoutValueContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */; }; 887AA0572A4253050089F517 /* RNILayoutKeyboardValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */; }; 887C3BE22A42F9E00026B57C /* CACornerMask+StaticAlias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887C3BE12A42F9E00026B57C /* CACornerMask+StaticAlias.swift */; }; + 887C3BE42A43C4FF0026B57C /* RNILayoutMargins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887C3BE32A43C4FF0026B57C /* RNILayoutMargins.swift */; }; + 887C3BE62A43C5460026B57C /* RNILayoutMarginRects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887C3BE52A43C5460026B57C /* RNILayoutMarginRects.swift */; }; 88A2EF742A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A2EF732A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift */; }; 88B7D0EF29C593F400490628 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0EE29C593F400490628 /* AppDelegate.swift */; }; 88B7D0F129C593F400490628 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0F029C593F400490628 /* SceneDelegate.swift */; }; @@ -120,6 +122,8 @@ 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValueContext.swift; sourceTree = ""; }; 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutKeyboardValues.swift; sourceTree = ""; }; 887C3BE12A42F9E00026B57C /* CACornerMask+StaticAlias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CACornerMask+StaticAlias.swift"; sourceTree = ""; }; + 887C3BE32A43C4FF0026B57C /* RNILayoutMargins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutMargins.swift; sourceTree = ""; }; + 887C3BE52A43C5460026B57C /* RNILayoutMarginRects.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutMarginRects.swift; sourceTree = ""; }; 88A2EF732A3A98F6006B5235 /* AdaptiveModalConfigTestPresets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalConfigTestPresets.swift; sourceTree = ""; }; 88B7D0EB29C593F400490628 /* swift-programmatic-modal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "swift-programmatic-modal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 88B7D0EE29C593F400490628 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -433,6 +437,8 @@ children = ( 88D017D72A1B302F004664D2 /* RNILayout.swift */, 88E8C01B2A23203E008C2FF8 /* RNILayoutPreset.swift */, + 887C3BE32A43C4FF0026B57C /* RNILayoutMargins.swift */, + 887C3BE52A43C5460026B57C /* RNILayoutMarginRects.swift */, 886AFCAA2A31FF40004AC9FB /* RNILayoutValue.swift */, 887AA0562A4253050089F517 /* RNILayoutKeyboardValues.swift */, 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */, @@ -689,11 +695,13 @@ 88D016602A14C86B004664D2 /* RootViewController.swift in Sources */, 88D0183E2A1B3030004664D2 /* CAAnimation+Block.swift in Sources */, 88D0184C2A1B3030004664D2 /* RNIAnimator.swift in Sources */, + 887C3BE42A43C4FF0026B57C /* RNILayoutMargins.swift in Sources */, 88D018362A1B3030004664D2 /* CGSize+Init.swift in Sources */, 886AFCB12A325B6F004AC9FB /* RNILayoutValueContext.swift in Sources */, 88B7D0EF29C593F400490628 /* AppDelegate.swift in Sources */, 88D018222A1B3030004664D2 /* UIImage+Init.swift in Sources */, 88D018702A1B3030004664D2 /* RNIModalFlags.swift in Sources */, + 887C3BE62A43C5460026B57C /* RNILayoutMarginRects.swift in Sources */, 88E8C01E2A234B0A008C2FF8 /* UIBezierPath+VariadicCornerRadius.swift in Sources */, 88B7D0F129C593F400490628 /* SceneDelegate.swift in Sources */, 88D0187E2A1B6CB3004664D2 /* BlurEffectTestViewController.swift in Sources */,