Skip to content

Commit

Permalink
💫 Update: Exp - AdaptiveModal
Browse files Browse the repository at this point in the history
Summary: Update experiment/test - `swift-programmatic-modal/AdaptiveModal`.
  • Loading branch information
dominicstop committed Jun 2, 2023
1 parent 4effe97 commit d124753
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ struct AdaptiveModalConfig {
case rightToLeft;
};

enum SnapPercentStrategy {
case index;
case position;
};

// MARK: - Properties
// ------------------

let snapPoints: [AdaptiveModalSnapPointConfig];
let snapDirection: Direction;

let snapPercentStrategy: SnapPercentStrategy;

// let snapPointInitial:

let snapAnimationConfig: AdaptiveModalSnapAnimationConfig;
Expand All @@ -35,18 +42,37 @@ struct AdaptiveModalConfig {
self.snapPoints.count - 1;
};

/// Defines which axis of the gesture point to use to drive the interpolation
/// of the modal snap points
///
var inputValueKeyForPoint: KeyPath<CGPoint, CGFloat> {
switch self.snapDirection {
case .topToBottom, .bottomToTop: return \.y;
case .leftToRight, .rightToLeft: return \.x;
};
};

var maxInputRangeKeyForRect: KeyPath<CGRect, CGFloat> {
switch self.snapDirection {
case .bottomToTop, .topToBottom: return \.height;
case .leftToRight, .rightToLeft: return \.width;
};
};

// MARK: - Init
// ------------

init(
snapPoints: [AdaptiveModalSnapPointConfig],
snapDirection: Direction,
snapPercentStrategy: SnapPercentStrategy = .position,
snapAnimationConfig: AdaptiveModalSnapAnimationConfig = .default,
interpolationClampingConfig: AdaptiveModalClampingConfig = .default,
overshootSnapPoint: AdaptiveModalSnapPointPreset? = nil
) {
self.snapPoints = snapPoints;
self.snapDirection = snapDirection;
self.snapPercentStrategy = snapPercentStrategy;

self.snapAnimationConfig = snapAnimationConfig;
self.interpolationClampingConfig = interpolationClampingConfig;
Expand All @@ -61,10 +87,10 @@ struct AdaptiveModalConfig {
func sortInterpolationSteps<T>(_ array: [T]) -> [T] {
switch self.snapDirection {
case .bottomToTop, .rightToLeft:
return array.reversed();
return array;

case .topToBottom, .leftToRight:
return array;
return array.reversed();
};
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import UIKit

struct AdaptiveModalInterpolationPoint: Equatable {

let modalConfigIndex: Int;
let percent: CGFloat;
let snapPointIndex: Int;

/// The computed frames of the modal based on the snap points
let computedRect: CGRect;
Expand All @@ -20,19 +21,54 @@ struct AdaptiveModalInterpolationPoint: Equatable {
let backgroundVisualEffect: UIVisualEffect?;

init(
modalConfigIndex: Int,
usingModalConfig modalConfig: AdaptiveModalConfig,
snapPointIndex: Int,
percent: CGFloat? = nil,
withTargetRect targetRect: CGRect,
currentSize: CGSize,
snapPointConfig: AdaptiveModalSnapPointConfig,
prevSnapPointConfig: AdaptiveModalSnapPointConfig? = nil
) {
self.modalConfigIndex = modalConfigIndex;
self.snapPointIndex = snapPointIndex;

self.computedRect = snapPointConfig.snapPoint.computeRect(
let computedRect = snapPointConfig.snapPoint.computeRect(
withTargetRect: targetRect,
currentSize: currentSize
);

self.computedRect = computedRect;

self.percent = percent ?? {
switch modalConfig.snapPercentStrategy {
case .position:
let shouldInvertPercent: Bool = {
switch modalConfig.snapDirection {
case .bottomToTop, .rightToLeft: return true;
default: return false;
};
}();

let maxRangeInput =
targetRect[keyPath: modalConfig.maxInputRangeKeyForRect];

let inputValue =
computedRect.origin[keyPath: modalConfig.inputValueKeyForPoint];

let percent = inputValue / maxRangeInput;

return shouldInvertPercent
? AdaptiveModalManager.invertPercent(percent)
: percent;

case .index:
let current = CGFloat(snapPointIndex + 1);
let max = CGFloat(modalConfig.snapPoints.count);

return current / max;
};
}();


let keyframeCurrent = snapPointConfig.animationKeyframe;
let keyframePrev = prevSnapPointConfig?.animationKeyframe;

Expand Down Expand Up @@ -76,14 +112,15 @@ extension AdaptiveModalInterpolationPoint {
currentSize: CGSize
) -> [Self] {

var items: [AdaptiveModalInterpolationPoint] = [];

var items: [AdaptiveModalInterpolationPoint] = [];
for (index, snapConfig) in modalConfig.snapPoints.enumerated() {
let prevSnapConfig = modalConfig.snapPoints[safeIndex: index];

items.append(
AdaptiveModalInterpolationPoint(
modalConfigIndex: index,
usingModalConfig: modalConfig,
snapPointIndex: index,
withTargetRect: targetRect,
currentSize: currentSize,
snapPointConfig: snapConfig,
Expand All @@ -95,18 +132,20 @@ extension AdaptiveModalInterpolationPoint {
items.append({
let prevSnapPointConfig = modalConfig.snapPoints.last!;

let snapPointConfig = AdaptiveModalSnapPointConfig(
let overshootSnapPointConfig = AdaptiveModalSnapPointConfig(
fromSnapPointPreset: modalConfig.overshootSnapPoint,
fromBaseLayoutConfig: prevSnapPointConfig.snapPoint,
withTargetRect: targetRect,
currentSize: currentSize
);

return AdaptiveModalInterpolationPoint(
modalConfigIndex: modalConfig.snapPointLastIndex + 1,
usingModalConfig: modalConfig,
snapPointIndex: modalConfig.snapPointLastIndex + 1,
percent: 1,
withTargetRect: targetRect,
currentSize: currentSize,
snapPointConfig: snapPointConfig,
snapPointConfig: overshootSnapPointConfig,
prevSnapPointConfig: prevSnapPointConfig
);
}());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,9 @@ extension AdaptiveModalManager {
? position + displacement
: position - displacement;
};

static func invertPercent(_ percent: CGFloat) -> CGFloat {
let offset = percent > 1 ? abs(percent - 1) : 0;
return 1 - percent + offset;
};
};
Loading

0 comments on commit d124753

Please sign in to comment.