Commit 5a76e020 by Daniel Dahan

finished preprocessors

parent b0e21e3b
...@@ -102,13 +102,12 @@ fileprivate extension Motion { ...@@ -102,13 +102,12 @@ fileprivate extension Motion {
/// Prepares the preprocessors. /// Prepares the preprocessors.
func preparePreprocessors() { func preparePreprocessors() {
for x in [ for x in [IgnoreSubviewTransitionsPreprocessor(),
IgnoreSubviewTransitionsPreprocessor(), ConditionalPreprocessor(),
TransitionPreprocessor(),
MatchPreprocessor(), MatchPreprocessor(),
SourcePreprocessor(), SourcePreprocessor(),
CascadePreprocessor(), CascadePreprocessor()] as [MotionPreprocessor] {
TransitionPreprocessor(motion: self),
DurationPreprocessor()] as [MotionPreprocessor] {
preprocessors.append(x) preprocessors.append(x)
} }
......
...@@ -441,7 +441,7 @@ public extension Motion { ...@@ -441,7 +441,7 @@ public extension Motion {
} }
let s = MotionTransitionState(transitions: transitions) let s = MotionTransitionState(transitions: transitions)
let v = context.transitionPairedView(for: view) ?? view let v = context.pairedView(for: view) ?? view
for a in animators { for a in animators {
a.apply(state: s, to: v) a.apply(state: s, to: v)
......
...@@ -148,7 +148,7 @@ public extension MotionContext { ...@@ -148,7 +148,7 @@ public extension MotionContext {
source and destination view controllers. source and destination view controllers.
- Returns: An optional UIView. - Returns: An optional UIView.
*/ */
func transitionPairedView(for view: UIView) -> UIView? { func pairedView(for view: UIView) -> UIView? {
if let i = view.motionIdentifier { if let i = view.motionIdentifier {
if view == sourceView(for: i) { if view == sourceView(for: i) {
return destinationView(for: i) return destinationView(for: i)
...@@ -316,7 +316,7 @@ public extension MotionContext { ...@@ -316,7 +316,7 @@ public extension MotionContext {
hide(view: view) hide(view: view)
} }
if let pairedView = transitionPairedView(for: view), let pairedSnapshot = viewToSnapshot[pairedView] { if let pairedView = pairedView(for: view), let pairedSnapshot = viewToSnapshot[pairedView] {
let siblingViews = pairedView.superview!.subviews let siblingViews = pairedView.superview!.subviews
let nextSiblings = siblingViews[siblingViews.index(of: pairedView)! + 1..<siblingViews.count] let nextSiblings = siblingViews[siblingViews.index(of: pairedView)! + 1..<siblingViews.count]
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import UIKit import UIKit
class MotionPlugin: BaseMotionPreprocessor, MotionAnimator { class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
/** /**
Determines whether or not to receive `seekTo` callback on every frame. Determines whether or not to receive `seekTo` callback on every frame.
......
...@@ -45,6 +45,9 @@ public struct MotionTransitionState { ...@@ -45,6 +45,9 @@ public struct MotionTransitionState {
/// The initial state that the transition will start at. /// The initial state that the transition will start at.
internal var beginState: MotionTransitionStateWrapper? internal var beginState: MotionTransitionStateWrapper?
public var conditionalTransitions: [((MotionConditionalContext) -> Bool, [MotionTransition])]?
/// The start state if there is a match in the desition view controller. /// The start state if there is a match in the desition view controller.
public var beginStateIfMatched: [MotionTransition]? public var beginStateIfMatched: [MotionTransition]?
......
...@@ -60,7 +60,7 @@ public enum CascadeDirection { ...@@ -60,7 +60,7 @@ public enum CascadeDirection {
} }
} }
class CascadePreprocessor: BaseMotionPreprocessor { class CascadePreprocessor: MotionCorePreprocessor {
/** /**
Processes the transitionary views. Processes the transitionary views.
- Parameter fromViews: An Array of UIViews. - Parameter fromViews: An Array of UIViews.
...@@ -91,10 +91,10 @@ class CascadePreprocessor: BaseMotionPreprocessor { ...@@ -91,10 +91,10 @@ class CascadePreprocessor: BaseMotionPreprocessor {
let delay = TimeInterval(i) * deltaTime + initialDelay let delay = TimeInterval(i) * deltaTime + initialDelay
func applyDelay(view: UIView) { func applyDelay(view: UIView) {
if context.transitionPairedView(for: view) == nil { if context.pairedView(for: view) == nil {
context[view]?.delay = delay context[view]?.delay = delay
} else if delayMatchedViews, let paired = context.transitionPairedView(for: view) { } else if delayMatchedViews, let paired = context.pairedView(for: view) {
context[view]?.delay = finalDelay context[view]?.delay = finalDelay
context[paired]?.delay = finalDelay context[paired]?.delay = finalDelay
} }
......
/*
* The MIT License (MIT)
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import UIKit
public struct MotionConditionalContext {
internal weak var motion: Motion!
public weak var view: UIView!
public private(set) var isAppearing: Bool
public var isPresenting: Bool {
return motion.isPresenting
}
public var isTabBarController: Bool {
return motion.isTabBarController
}
public var isNavigationController: Bool {
return motion.isNavigationController
}
public var isMatched: Bool {
return matchedView != nil
}
public var isAncestorViewMatched: Bool {
return matchedAncestorView != nil
}
public var matchedView: UIView? {
return motion.context.pairedView(for: view)
}
public var matchedAncestorView: (UIView, UIView)? {
var current = view.superview
while let ancestor = current, ancestor != motion.context.container {
if let pairedView = motion.context.pairedView(for: ancestor) {
return (ancestor, pairedView)
}
current = ancestor.superview
}
return nil
}
public var fromViewController: UIViewController {
return motion.fromViewController!
}
public var toViewController: UIViewController {
return motion.toViewController!
}
public var currentViewController: UIViewController {
return isAppearing ? toViewController : fromViewController
}
public var otherViewController: UIViewController {
return isAppearing ? fromViewController : toViewController
}
}
class ConditionalPreprocessor: MotionCorePreprocessor {
override func process(fromViews: [UIView], toViews: [UIView]) {
process(views: fromViews, isAppearing: false)
process(views: toViews, isAppearing: true)
}
func process(views: [UIView], isAppearing: Bool) {
for v in views {
guard let conditionalTransitions = context[v]?.conditionalTransitions else {
continue
}
for (condition, transitions) in conditionalTransitions {
if condition(MotionConditionalContext(motion: motion, view: v, isAppearing: isAppearing)) {
context[v]!.append(contentsOf: transitions)
}
}
}
}
}
/*
* The MIT License (MIT)
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import UIKit
class DurationPreprocessor: BaseMotionPreprocessor {
/**
Processes the transitionary views.
- Parameter fromViews: An Array of UIViews.
- Parameter toViews: An Array of UIViews.
*/
override func process(fromViews: [UIView], toViews: [UIView]) {
var maxDuration: TimeInterval = 0
maxDuration = applyOptimizedDurationIfNoDuration(views: fromViews)
maxDuration = max(maxDuration, applyOptimizedDurationIfNoDuration(views: toViews))
setDurationForInfiniteDuration(views: fromViews, duration: maxDuration)
setDurationForInfiniteDuration(views: toViews, duration: maxDuration)
}
/**
Retrieves the optimized duration for a given UIView.
- Parameter for view: A UIView.
- Returns: A TimeInterval.
*/
func optimizedDuration(for view: UIView) -> TimeInterval {
let v = context[view]!
return view.optimizedDuration(position: context.container.convert(view.layer.position, from: view.superview),
size: v.size,
transform: v.transform)
}
/**
Applies the optimized duration for an Array of UIViews.
- Parameter views: An Array of UIViews.
- Returns: A TimeInterval.
*/
func applyOptimizedDurationIfNoDuration(views: [UIView]) -> TimeInterval {
var d: TimeInterval = 0
for v in views where nil != context[v] {
if nil == context[v]?.duration {
context[v]!.duration = optimizedDuration(for: v)
}
d = .infinity == context[v]!.duration! ?
max(d, optimizedDuration(for: v)) :
max(d, context[v]!.duration!)
}
return d
}
/**
Sets the duration if the duration of a transition is set to `.infinity`.
- Parameter views: An Array of UIViews.
- Parameter duration: A TimeInterval.
*/
func setDurationForInfiniteDuration(views: [UIView], duration: TimeInterval) {
for v in views where .infinity == context[v]?.duration {
context[v]!.duration = duration
}
}
}
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import UIKit import UIKit
class IgnoreSubviewTransitionsPreprocessor: BaseMotionPreprocessor { class IgnoreSubviewTransitionsPreprocessor: MotionCorePreprocessor {
/** /**
Processes the transitionary views. Processes the transitionary views.
- Parameter fromViews: An Array of UIViews. - Parameter fromViews: An Array of UIViews.
...@@ -64,12 +64,12 @@ class IgnoreSubviewTransitionsPreprocessor: BaseMotionPreprocessor { ...@@ -64,12 +64,12 @@ class IgnoreSubviewTransitionsPreprocessor: BaseMotionPreprocessor {
} }
} }
extension IgnoreSubviewTransitionsPreprocessor { fileprivate extension IgnoreSubviewTransitionsPreprocessor {
/** /**
Clears the transition for a given view's subviews. Clears the transition for a given view's subviews.
- Parameter for view: A UIView. - Parameter for view: A UIView.
*/ */
fileprivate func cleanSubviewTransitions(for view: UIView) { func cleanSubviewTransitions(for view: UIView) {
for v in view.subviews { for v in view.subviews {
context[v] = nil context[v] = nil
cleanSubviewTransitions(for: v) cleanSubviewTransitions(for: v)
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import UIKit import UIKit
class MatchPreprocessor: BaseMotionPreprocessor { class MatchPreprocessor: MotionCorePreprocessor {
/** /**
Processes the transitionary views. Processes the transitionary views.
- Parameter fromViews: An Array of UIViews. - Parameter fromViews: An Array of UIViews.
...@@ -36,23 +36,17 @@ class MatchPreprocessor: BaseMotionPreprocessor { ...@@ -36,23 +36,17 @@ class MatchPreprocessor: BaseMotionPreprocessor {
*/ */
override func process(fromViews: [UIView], toViews: [UIView]) { override func process(fromViews: [UIView], toViews: [UIView]) {
for tv in toViews { for tv in toViews {
guard let i = tv.motionIdentifier, let fv = context.sourceView(for: i) else { continue } guard let motionIdentifier = tv.motionIdentifier, let fv = context.sourceView(for: motionIdentifier) else {
continue
}
var tvState = context[tv] ?? MotionTransitionState() var tvState = context[tv] ?? MotionTransitionState()
var fvState = context[fv] ?? MotionTransitionState() var fvState = context[fv] ?? MotionTransitionState()
if let v = tvState.beginStateIfMatched { // match is just a two-way source effect
tvState.append(.beginWith(transitions: v)) tvState.motionIdentifier = motionIdentifier
} fvState.motionIdentifier = motionIdentifier
if let v = fvState.beginStateIfMatched {
fvState.append(.beginWith(transitions: v))
}
tvState.motionIdentifier = i
tvState.opacity = 0
fvState.motionIdentifier = i
fvState.arc = tvState.arc fvState.arc = tvState.arc
fvState.duration = tvState.duration fvState.duration = tvState.duration
fvState.timingFunction = tvState.timingFunction fvState.timingFunction = tvState.timingFunction
...@@ -62,22 +56,36 @@ class MatchPreprocessor: BaseMotionPreprocessor { ...@@ -62,22 +56,36 @@ class MatchPreprocessor: BaseMotionPreprocessor {
let forceNonFade = tvState.nonFade || fvState.nonFade let forceNonFade = tvState.nonFade || fvState.nonFade
let isNonOpaque = !fv.isOpaque || fv.alpha < 1 || !tv.isOpaque || tv.alpha < 1 let isNonOpaque = !fv.isOpaque || fv.alpha < 1 || !tv.isOpaque || tv.alpha < 1
if !forceNonFade && isNonOpaque { if context.insertToViewFirst {
// Cross fade if from/toViews are not opaque.
fvState.opacity = 0 fvState.opacity = 0
if !forceNonFade && isNonOpaque {
tvState.opacity = 0
} else { } else {
// No cross fade in this case, fromView is always displayed during the transition. tvState.opacity = nil
if !tv.layer.masksToBounds && tvState.displayShadow {
fvState.displayShadow = false
}
}
} else {
tvState.opacity = 0
if !forceNonFade && isNonOpaque {
// cross fade if from/toViews are not opaque
fvState.opacity = 0
} else {
// no cross fade in this case, fromView is always displayed during the transition.
fvState.opacity = nil fvState.opacity = nil
/** // we dont want two shadows showing up. Therefore we disable toView's shadow when fromView is able to display its shadow
We dont want two shadows showing up. Therefore we disable toView's
shadow when fromView is able to display its shadow.
*/
if !fv.layer.masksToBounds && fvState.displayShadow { if !fv.layer.masksToBounds && fvState.displayShadow {
tvState.displayShadow = false tvState.displayShadow = false
} }
} }
}
context[tv] = tvState context[tv] = tvState
context[fv] = fvState context[fv] = fvState
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import UIKit import UIKit
class BaseMotionPreprocessor: MotionPreprocessor { class MotionCorePreprocessor: MotionPreprocessor {
weak public var motion: Motion! weak public var motion: Motion!
/// A reference to the MotionContext. /// A reference to the MotionContext.
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import UIKit import UIKit
class SourcePreprocessor: BaseMotionPreprocessor { class SourcePreprocessor: MotionCorePreprocessor {
/** /**
Processes the transitionary views. Processes the transitionary views.
- Parameter fromViews: An Array of UIViews. - Parameter fromViews: An Array of UIViews.
......
...@@ -172,16 +172,7 @@ public enum MotionTransitionType { ...@@ -172,16 +172,7 @@ public enum MotionTransitionType {
} }
} }
class TransitionPreprocessor: BaseMotionPreprocessor { class TransitionPreprocessor: MotionCorePreprocessor {
/**
An initializer that accepts a given Motion instance.
- Parameter motion: A Motion.
*/
init(motion: Motion) {
super.init()
self.motion = motion
}
/** /**
Processes the transitionary views. Processes the transitionary views.
- Parameter fromViews: An Array of UIViews. - Parameter fromViews: An Array of UIViews.
......
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