Commit 83ab6b00 by Daniel Dahan

UIViewController.motionModalTransitionType renamed to UIViewController.motionTransitionType

parent b9a25764
## 1.2.5
* `UIViewController.motionModalTransitionType` renamed to `UIViewController.motionTransitionType`.
## 1.2.4
* Added begin / end transition methods for from / to view controllers.
......
......@@ -33,24 +33,24 @@ fileprivate var AssociatedInstanceKey: UInt8 = 0
fileprivate struct AssociatedInstance {
/// A reference to the modal animation.
var modalTransitionType: MotionTransitionType
/// A reference to the navigation animation.
var navigationTransitionType: MotionTransitionType
/// A reference to the tabBar animation.
var tabBarTransitionType: MotionTransitionType
/// A reference to the stored snapshot.
var storedSnapshot: UIView?
/**
A reference to the previous navigation controller delegate
/**
A reference to the previous navigation controller delegate
before Motion was enabled.
*/
weak var previousNavigationDelegate: UINavigationControllerDelegate?
/**
A reference to the previous tab bar controller delegate
A reference to the previous tab bar controller delegate
before Motion was enabled.
*/
weak var previousTabBarDelegate: UITabBarControllerDelegate?
......@@ -73,9 +73,9 @@ extension UIViewController {
AssociatedObject.set(base: self, key: &AssociatedInstanceKey, value: value)
}
}
/// default motion animation type for presenting & dismissing modally
public var motionModalTransitionType: MotionTransitionType {
/// Default motion animation type for presenting & dismissing modally.
public var motionTransitionType: MotionTransitionType {
get {
return associatedInstance.modalTransitionType
}
......@@ -83,8 +83,8 @@ extension UIViewController {
associatedInstance.modalTransitionType = value
}
}
/// used for .overFullScreen presentation
/// Used for .overFullScreen presentation.
internal var motionStoredSnapshot: UIView? {
get {
return associatedInstance.storedSnapshot
......@@ -93,7 +93,7 @@ extension UIViewController {
associatedInstance.storedSnapshot = value
}
}
/**
A reference to the previous navigation controller delegate
before Motion was enabled.
......@@ -184,8 +184,8 @@ extension UITabBarController {
extension UIViewController {
/**
Dismiss the current view controller with animation. Will perform a
navigationController.popViewController if the current view controller
Dismiss the current view controller with animation. Will perform a
navigationController.popViewController if the current view controller
is contained inside a navigationController
*/
@IBAction
......@@ -196,33 +196,41 @@ extension UIViewController {
dismiss(animated: true)
}
}
/// Unwind to the root view controller using Motion.
@IBAction
public func motionUnwindToRootViewController() {
motionUnwindToViewController { $0.presentingViewController == nil }
motionUnwindToViewController {
nil == $0.presentingViewController
}
}
/// Unwind to a specific view controller using Motion.
public func motionUnwindToViewController(_ toViewController: UIViewController) {
motionUnwindToViewController { $0 == toViewController }
motionUnwindToViewController {
$0 == toViewController
}
}
/// Unwind to a view controller that responds to the given selector using Motion.
public func motionUnwindToViewController(withSelector: Selector) {
motionUnwindToViewController { $0.responds(to: withSelector) }
motionUnwindToViewController {
$0.responds(to: withSelector)
}
}
/// Unwind to a view controller with given class using Motion
public func motionUnwindToViewController(withClass: AnyClass) {
motionUnwindToViewController { $0.isKind(of: withClass) }
motionUnwindToViewController {
$0.isKind(of: withClass)
}
}
/// Unwind to a view controller that the matchBlock returns true on.
public func motionUnwindToViewController(withMatchBlock: (UIViewController) -> Bool) {
var target: UIViewController?
var current: UIViewController? = self
while nil == target && nil != current {
if let childViewControllers = (current as? UINavigationController)?.childViewControllers ?? current!.navigationController?.childViewControllers {
for v in childViewControllers.reversed() {
......@@ -232,34 +240,34 @@ extension UIViewController {
}
}
}
guard nil == target else {
continue
}
current = current?.presentingViewController
guard let v = current, withMatchBlock(v) else {
continue
}
target = v
}
guard let v = target else {
return
}
guard nil != v.presentedViewController else {
v.navigationController?.popToViewController(v, animated: true)
return
}
v.navigationController?.popToViewController(v, animated: false)
let fromVC = navigationController ?? self
let toVC = v.navigationController ?? v
if v.presentedViewController != fromVC {
/**
UIKit's UIViewController.dismiss will jump to target.presentedViewController then perform the dismiss.
......@@ -267,17 +275,17 @@ extension UIViewController {
And also force Motion to use the current view controller as the fromViewController.
*/
Motion.shared.fromViewController = fromVC
guard let snapshot = fromVC.view.snapshotView(afterScreenUpdates: true) else {
return
}
toVC.presentedViewController?.view.addSubview(snapshot)
}
toVC.dismiss(animated: true)
}
/**
Replace the current view controller with another view controller within the
navigation/modal stack.
......@@ -288,35 +296,35 @@ extension UIViewController {
print("motionReplaceViewController cancelled because Motion was doing a transition. Use Motion.shared.cancel(animated: false) or Motion.shared.end(animated: false) to stop the transition first before calling motionReplaceViewController.")
return
}
if let nc = navigationController {
var v = nc.childViewControllers
if !v.isEmpty {
v.removeLast()
v.append(next)
}
if nc.isMotionEnabled {
Motion.shared.forceNonInteractive = true
}
nc.setViewControllers(v, animated: true)
} else if let container = view.superview {
let presentingVC = presentingViewController
Motion.shared.transition(from: self, to: next, in: container) { [weak self] (isFinished) in
guard isFinished else {
return
}
UIApplication.shared.keyWindow?.addSubview(next.view)
guard let pvc = presentingVC else {
UIApplication.shared.keyWindow?.rootViewController = next
return
}
self?.dismiss(animated: false) {
pvc.present(next, animated: false)
}
......
......@@ -35,7 +35,7 @@ public enum MotionTransitionType {
case up
case down
}
case none
case auto
case push(direction: Direction)
......@@ -51,7 +51,7 @@ public enum MotionTransitionType {
case zoomOut
indirect case selectBy(presenting: MotionTransitionType, dismissing: MotionTransitionType)
/**
Sets the presenting and dismissing transitions.
- Parameter presenting: A MotionTransitionType.
......@@ -60,109 +60,109 @@ public enum MotionTransitionType {
public static func autoReverse(presenting: MotionTransitionType) -> MotionTransitionType {
return .selectBy(presenting: presenting, dismissing: presenting.reversed())
}
/// Returns a reversal transition.
func reversed() -> MotionTransitionType {
switch self {
case .push(direction: .up):
return .pull(direction: .down)
case .push(direction: .right):
return .pull(direction: .left)
case .push(direction: .down):
return .pull(direction: .up)
case .push(direction: .left):
return .pull(direction: .right)
case .pull(direction: .up):
return .push(direction: .down)
case .pull(direction: .right):
return .push(direction: .left)
case .pull(direction: .down):
return .push(direction: .up)
case .pull(direction: .left):
return .push(direction: .right)
case .cover(direction: .up):
return .uncover(direction: .down)
case .cover(direction: .right):
return .uncover(direction: .left)
case .cover(direction: .down):
return .uncover(direction: .up)
case .cover(direction: .left):
return .uncover(direction: .right)
case .uncover(direction: .up):
return .cover(direction: .down)
case .uncover(direction: .right):
return .cover(direction: .left)
case .uncover(direction: .down):
return .cover(direction: .up)
case .uncover(direction: .left):
return .cover(direction: .right)
case .slide(direction: .up):
return .slide(direction: .down)
case .slide(direction: .down):
return .slide(direction: .up)
case .slide(direction: .left):
return .slide(direction: .right)
case .slide(direction: .right):
return .slide(direction: .left)
case .zoomSlide(direction: .up):
return .zoomSlide(direction: .down)
case .zoomSlide(direction: .down):
return .zoomSlide(direction: .up)
case .zoomSlide(direction: .left):
return .zoomSlide(direction: .right)
case .zoomSlide(direction: .right):
return .zoomSlide(direction: .left)
case .pageIn(direction: .up):
return .pageOut(direction: .down)
case .pageIn(direction: .right):
return .pageOut(direction: .left)
case .pageIn(direction: .down):
return .pageOut(direction: .up)
case .pageIn(direction: .left):
return .pageOut(direction: .right)
case .pageOut(direction: .up):
return .pageIn(direction: .down)
case .pageOut(direction: .right):
return .pageIn(direction: .left)
case .pageOut(direction: .down):
return .pageIn(direction: .up)
case .pageOut(direction: .left):
return .pageIn(direction: .right)
case .zoom:
return .zoomOut
case .zoomOut:
return .zoom
......@@ -175,7 +175,7 @@ public enum MotionTransitionType {
class TransitionPreprocessor: MotionPreprocessor {
/// A reference to a MotionContext.
weak var context: MotionContext!
/// A reference to a Motion.
weak var motion: Motion?
......@@ -196,15 +196,15 @@ class TransitionPreprocessor: MotionPreprocessor {
guard let m = motion else {
return
}
guard let fv = m.fromView else {
return
}
guard let tv = m.toView else {
return
}
var defaultAnimation = m.defaultAnimation
let isNavigationController = m.isNavigationController
let isTabBarController = m.isTabBarController
......@@ -214,15 +214,15 @@ class TransitionPreprocessor: MotionPreprocessor {
let fromOverFullScreen = m.fromOverFullScreen
let toOverFullScreen = m.toOverFullScreen
let animators = m.animators
if case .auto = defaultAnimation {
if isNavigationController, let navAnim = toViewController?.navigationController?.motionNavigationTransitionType {
defaultAnimation = navAnim
} else if isTabBarController, let tabAnim = toViewController?.tabBarController?.motionTabBarTransitionType {
defaultAnimation = tabAnim
} else if let modalAnim = (isPresenting ? toViewController : fromViewController)?.motionModalTransitionType {
} else if let modalAnim = (isPresenting ? toViewController : fromViewController)?.motionTransitionType {
defaultAnimation = modalAnim
}
}
......@@ -234,13 +234,13 @@ class TransitionPreprocessor: MotionPreprocessor {
if case .auto = defaultAnimation {
if animators.contains(where: { $0.canAnimate(view: tv, isAppearing: true) || $0.canAnimate(view: fv, isAppearing: false) }) {
defaultAnimation = .none
} else if isNavigationController {
defaultAnimation = isPresenting ? .push(direction:.left) : .pull(direction:.right)
} else if isTabBarController {
defaultAnimation = isPresenting ? .slide(direction:.left) : .slide(direction:.right)
} else {
defaultAnimation = .fade
}
......@@ -258,76 +258,76 @@ class TransitionPreprocessor: MotionPreprocessor {
.shadow(radius: 5),
.shadow(offset: .zero),
.masksToBounds(false)]
switch defaultAnimation {
case .push(let direction):
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false) / 3),
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
case .pull(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true) / 3),
.overlay(color: .black, opacity: 0.1)])
case .slide(let direction):
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false))])
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true))])
case .zoomSlide(let direction):
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false)), .scale(0.8)])
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true)), .scale(0.8)])
case .cover(let direction):
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
case .uncover(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.overlay(color: .black, opacity: 0.1)])
case .pageIn(let direction):
context[tv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.scale(0.7),
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
case .pageOut(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.scale(0.7),
.overlay(color: .black, opacity: 0.1)])
case .fade:
// TODO: clean up this. overFullScreen logic shouldn't be here
if !(fromOverFullScreen && !isPresenting) {
......@@ -344,21 +344,21 @@ class TransitionPreprocessor: MotionPreprocessor {
context[tv]!.append(.preferredDurationMatchesLongest)
context[fv]!.append(.preferredDurationMatchesLongest)
case .zoom:
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.scale(1.3), .fadeOut])
context[tv]!.append(contentsOf: [.scale(0.7)])
case .zoomOut:
context[tv]!.append(contentsOf: [.scale(1.3), .fadeOut])
context[fv]!.append(contentsOf: [.scale(0.7)])
default:
fatalError("Not implemented")
}
}
/**
Shifts the transition by a given size.
- Parameter direction: A MotionTransitionType.Direction.
......@@ -372,19 +372,19 @@ class TransitionPreprocessor: MotionPreprocessor {
func shift(direction: MotionTransitionType.Direction, isAppearing: Bool, size: CGSize? = nil, transpose: Bool = false) -> CGPoint {
let size = size ?? context.container.bounds.size
let point: CGPoint
switch direction {
case .left, .right:
point = CGPoint(x: (.right == direction) == isAppearing ? -size.width : size.width, y: 0)
case .up, .down:
point = CGPoint(x: 0, y: (.down == direction) == isAppearing ? -size.height : size.height)
}
if transpose {
return CGPoint(x: point.y, y: point.x)
}
return point
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment