Skip to content
This repository has been archived by the owner on Aug 13, 2021. It is now read-only.

Commit

Permalink
Add foreAlignmentEdge property to TransitionController.
Browse files Browse the repository at this point in the history
Summary:
If a view controller has a non-zero preferredContentSize, then the foreAlignmentEdge will be used to align the view to either the center of the screen, if nil, or to the specified edge (one of minX, minY, maxX, or maxY).

If preferredContentSize is zero, then the transition's `finalFrame` value will be used instead - this is generally the containerView's bounds.

This API is useful for building modal dialogs and sliding drawers that are presented over the current context with `modalPresentationStyle = .overCurrentContext`.

Reviewers: O2 Material Motion, O4 Material Apple platform reviewers, #material_motion, markwei

Reviewed By: O2 Material Motion, O4 Material Apple platform reviewers, #material_motion, markwei

Subscribers: markwei

Tags: #material_motion

Differential Revision: http://codereview.cc/D3067
  • Loading branch information
Jeff Verkoeyen committed Apr 20, 2017
1 parent e2ad598 commit 3498a0f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
13 changes: 3 additions & 10 deletions examples/ModalDialogExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ModalDialogViewController: UIViewController {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

transitionController.transitionType = ModalDialogTransition.self

preferredContentSize = .init(width: 200, height: 200)
modalPresentationStyle = .overCurrentContext
}

Expand All @@ -64,8 +64,6 @@ class ModalDialogViewController: UIViewController {
view.layer.shadowRadius = 5
view.layer.shadowOpacity = 1
view.layer.shadowOffset = .init(width: 0, height: 2)

preferredContentSize = .init(width: 200, height: 200)
}
}

Expand All @@ -74,15 +72,10 @@ class ModalDialogTransition: SelfDismissingTransition {
required init() {}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
let size = ctx.fore.preferredContentSize

if ctx.direction == .forward {
ctx.fore.view.bounds = CGRect(origin: .zero, size: size)
}

let size = ctx.fore.view.frame.size
let bounds = ctx.containerView().bounds
let backPosition = CGPoint(x: bounds.midX, y: bounds.maxY + size.height * 3 / 4)
let forePosition = CGPoint(x: bounds.midX, y: bounds.midY)
let forePosition = ctx.fore.view.layer.position

let reactiveForeLayer = runtime.get(ctx.fore.view.layer)
let position = reactiveForeLayer.position
Expand Down
40 changes: 38 additions & 2 deletions src/transitions/TransitionContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ public final class TransitionContext: NSObject {
*/
public let fore: UIViewController

public let foreAlignmentEdge: CGRectEdge?

/** The set of gesture recognizers associated with this transition. */
public let gestureRecognizers: Set<UIGestureRecognizer>

Expand All @@ -96,12 +98,14 @@ public final class TransitionContext: NSObject {
direction: TransitionDirection,
back: UIViewController,
fore: UIViewController,
gestureRecognizers: Set<UIGestureRecognizer>) {
gestureRecognizers: Set<UIGestureRecognizer>,
foreAlignmentEdge: CGRectEdge?) {
self.direction = createProperty("Transition.direction", withInitialValue: direction)
self.initialDirection = direction
self.back = back
self.fore = fore
self.gestureRecognizers = gestureRecognizers
self.foreAlignmentEdge = foreAlignmentEdge
self.window = TransitionTimeWindow(duration: TransitionContext.defaultDuration)

// TODO: Create a Timeline.
Expand Down Expand Up @@ -140,6 +144,30 @@ extension TransitionContext: UIViewControllerInteractiveTransitioning {
}
}

private func preferredFrame(for viewController: UIViewController,
inBounds bounds: CGRect,
alignmentEdge: CGRectEdge?) -> CGRect? {
guard viewController.preferredContentSize != .zero() else {
return nil
}

let size = viewController.preferredContentSize
let origin: CGPoint
switch alignmentEdge {
case nil: // Centered
origin = .init(x: bounds.midX - size.width / 2, y: bounds.midY - size.height / 2)
case .minXEdge?:
origin = .init(x: bounds.minX, y: bounds.midY - size.height / 2)
case .minYEdge?:
origin = .init(x: bounds.midX - size.width / 2, y: bounds.minY)
case .maxXEdge?:
origin = .init(x: bounds.maxX - size.width, y: bounds.midY - size.height / 2)
case .maxYEdge?:
origin = .init(x: bounds.midX - size.width / 2, y: bounds.maxY - size.height)
}
return .init(origin: origin, size: size)
}

extension TransitionContext {
fileprivate func initiateTransition() {
if let from = context.viewController(forKey: .from) {
Expand All @@ -150,7 +178,15 @@ extension TransitionContext {
}

if let to = context.viewController(forKey: .to) {
let finalFrame = context.finalFrame(for: to)
let finalFrame: CGRect

if let preferredFrame = preferredFrame(for: to,
inBounds: context.containerView.bounds,
alignmentEdge: (direction.value == .forward) ? foreAlignmentEdge : nil) {
finalFrame = preferredFrame
} else {
finalFrame = context.finalFrame(for: to)
}
if !finalFrame.isEmpty {
to.view.frame = finalFrame
}
Expand Down
9 changes: 8 additions & 1 deletion src/transitions/TransitionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ public final class TransitionController {
get { return _transitioningDelegate.gestureDelegate.gestureRecognizers }
}

public var foreAlignmentEdge: CGRectEdge? {
set { _transitioningDelegate.foreAlignmentEdge = newValue }
get { return _transitioningDelegate.foreAlignmentEdge }
}

/**
The transitioning delegate managed by this controller.

Expand Down Expand Up @@ -152,6 +157,7 @@ private final class TransitioningDelegate: NSObject, UIViewControllerTransitioni
self.dismisser.delegate = self
}

var foreAlignmentEdge: CGRectEdge?
var ctx: TransitionContext?
var transitionType: Transition.Type?

Expand Down Expand Up @@ -180,7 +186,8 @@ private final class TransitioningDelegate: NSObject, UIViewControllerTransitioni
direction: direction,
back: back,
fore: fore,
gestureRecognizers: gestureDelegate.gestureRecognizers)
gestureRecognizers: gestureDelegate.gestureRecognizers,
foreAlignmentEdge: foreAlignmentEdge)
ctx?.delegate = self
}
}
Expand Down

0 comments on commit 3498a0f

Please sign in to comment.