Commit 5a76e020 by Daniel Dahan

finished preprocessors

parent b0e21e3b
......@@ -102,13 +102,12 @@ fileprivate extension Motion {
/// Prepares the preprocessors.
func preparePreprocessors() {
for x in [
IgnoreSubviewTransitionsPreprocessor(),
MatchPreprocessor(),
SourcePreprocessor(),
CascadePreprocessor(),
TransitionPreprocessor(motion: self),
DurationPreprocessor()] as [MotionPreprocessor] {
for x in [IgnoreSubviewTransitionsPreprocessor(),
ConditionalPreprocessor(),
TransitionPreprocessor(),
MatchPreprocessor(),
SourcePreprocessor(),
CascadePreprocessor()] as [MotionPreprocessor] {
preprocessors.append(x)
}
......
......@@ -441,7 +441,7 @@ public extension Motion {
}
let s = MotionTransitionState(transitions: transitions)
let v = context.transitionPairedView(for: view) ?? view
let v = context.pairedView(for: view) ?? view
for a in animators {
a.apply(state: s, to: v)
......
......@@ -148,7 +148,7 @@ public extension MotionContext {
source and destination view controllers.
- Returns: An optional UIView.
*/
func transitionPairedView(for view: UIView) -> UIView? {
func pairedView(for view: UIView) -> UIView? {
if let i = view.motionIdentifier {
if view == sourceView(for: i) {
return destinationView(for: i)
......@@ -316,7 +316,7 @@ public extension MotionContext {
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 nextSiblings = siblingViews[siblingViews.index(of: pairedView)! + 1..<siblingViews.count]
......
......@@ -28,7 +28,7 @@
import UIKit
class MotionPlugin: BaseMotionPreprocessor, MotionAnimator {
class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
/**
Determines whether or not to receive `seekTo` callback on every frame.
......
......@@ -45,6 +45,9 @@ public struct MotionTransitionState {
/// The initial state that the transition will start at.
internal var beginState: MotionTransitionStateWrapper?
public var conditionalTransitions: [((MotionConditionalContext) -> Bool, [MotionTransition])]?
/// The start state if there is a match in the desition view controller.
public var beginStateIfMatched: [MotionTransition]?
......
......@@ -60,7 +60,7 @@ public enum CascadeDirection {
}
}
class CascadePreprocessor: BaseMotionPreprocessor {
class CascadePreprocessor: MotionCorePreprocessor {
/**
Processes the transitionary views.
- Parameter fromViews: An Array of UIViews.
......@@ -91,10 +91,10 @@ class CascadePreprocessor: BaseMotionPreprocessor {
let delay = TimeInterval(i) * deltaTime + initialDelay
func applyDelay(view: UIView) {
if context.transitionPairedView(for: view) == nil {
if context.pairedView(for: view) == nil {
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[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 @@
import UIKit
class IgnoreSubviewTransitionsPreprocessor: BaseMotionPreprocessor {
class IgnoreSubviewTransitionsPreprocessor: MotionCorePreprocessor {
/**
Processes the transitionary views.
- Parameter fromViews: An Array of UIViews.
......@@ -64,12 +64,12 @@ class IgnoreSubviewTransitionsPreprocessor: BaseMotionPreprocessor {
}
}
extension IgnoreSubviewTransitionsPreprocessor {
fileprivate extension IgnoreSubviewTransitionsPreprocessor {
/**
Clears the transition for a given view's subviews.
- Parameter for view: A UIView.
*/
fileprivate func cleanSubviewTransitions(for view: UIView) {
func cleanSubviewTransitions(for view: UIView) {
for v in view.subviews {
context[v] = nil
cleanSubviewTransitions(for: v)
......
......@@ -28,7 +28,7 @@
import UIKit
class MatchPreprocessor: BaseMotionPreprocessor {
class MatchPreprocessor: MotionCorePreprocessor {
/**
Processes the transitionary views.
- Parameter fromViews: An Array of UIViews.
......@@ -36,23 +36,17 @@ class MatchPreprocessor: BaseMotionPreprocessor {
*/
override func process(fromViews: [UIView], toViews: [UIView]) {
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 fvState = context[fv] ?? MotionTransitionState()
if let v = tvState.beginStateIfMatched {
tvState.append(.beginWith(transitions: v))
}
if let v = fvState.beginStateIfMatched {
fvState.append(.beginWith(transitions: v))
}
tvState.motionIdentifier = i
tvState.opacity = 0
// match is just a two-way source effect
tvState.motionIdentifier = motionIdentifier
fvState.motionIdentifier = motionIdentifier
fvState.motionIdentifier = i
fvState.arc = tvState.arc
fvState.duration = tvState.duration
fvState.timingFunction = tvState.timingFunction
......@@ -62,20 +56,34 @@ class MatchPreprocessor: BaseMotionPreprocessor {
let forceNonFade = tvState.nonFade || fvState.nonFade
let isNonOpaque = !fv.isOpaque || fv.alpha < 1 || !tv.isOpaque || tv.alpha < 1
if !forceNonFade && isNonOpaque {
// Cross fade if from/toViews are not opaque.
if context.insertToViewFirst {
fvState.opacity = 0
if !forceNonFade && isNonOpaque {
tvState.opacity = 0
} else {
tvState.opacity = nil
if !tv.layer.masksToBounds && tvState.displayShadow {
fvState.displayShadow = false
}
}
} else {
// No cross fade in this case, fromView is always displayed during the transition.
fvState.opacity = nil
tvState.opacity = 0
/**
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 {
tvState.displayShadow = false
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
// 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 {
tvState.displayShadow = false
}
}
}
......
......@@ -28,7 +28,7 @@
import UIKit
class BaseMotionPreprocessor: MotionPreprocessor {
class MotionCorePreprocessor: MotionPreprocessor {
weak public var motion: Motion!
/// A reference to the MotionContext.
......
......@@ -28,7 +28,7 @@
import UIKit
class SourcePreprocessor: BaseMotionPreprocessor {
class SourcePreprocessor: MotionCorePreprocessor {
/**
Processes the transitionary views.
- Parameter fromViews: An Array of UIViews.
......
......@@ -172,16 +172,7 @@ public enum MotionTransitionType {
}
}
class TransitionPreprocessor: BaseMotionPreprocessor {
/**
An initializer that accepts a given Motion instance.
- Parameter motion: A Motion.
*/
init(motion: Motion) {
super.init()
self.motion = motion
}
class TransitionPreprocessor: MotionCorePreprocessor {
/**
Processes the transitionary views.
- 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