Commit 104aead0 by Daniel Dahan

updated MotionTransition extensions before full review

parent 150344a1
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
965FE98D1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */; }; 965FE98D1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */; };
965FE9911FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */; }; 965FE9911FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */; };
965FE9931FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */; }; 965FE9931FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */; };
965FE9A11FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9A01FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift */; };
965FE9A31FE4407D0098BDD0 /* MotionTransition+Interactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965FE9A21FE4407D0098BDD0 /* MotionTransition+Interactive.swift */; };
96E409651F24F7370015A2B5 /* MotionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093D1F24F7370015A2B5 /* MotionAnimator.swift */; }; 96E409651F24F7370015A2B5 /* MotionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093D1F24F7370015A2B5 /* MotionAnimator.swift */; };
96E409661F24F7370015A2B5 /* MotionAnimatorViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093E1F24F7370015A2B5 /* MotionAnimatorViewContext.swift */; }; 96E409661F24F7370015A2B5 /* MotionAnimatorViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093E1F24F7370015A2B5 /* MotionAnimatorViewContext.swift */; };
96E409671F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093F1F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift */; }; 96E409671F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093F1F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift */; };
...@@ -104,6 +106,8 @@ ...@@ -104,6 +106,8 @@
965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UIViewControllerTransitioningDelegate.swift"; sourceTree = "<group>"; }; 965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UIViewControllerTransitioningDelegate.swift"; sourceTree = "<group>"; };
965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UITabBarControllerDelegate.swift"; sourceTree = "<group>"; }; 965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UITabBarControllerDelegate.swift"; sourceTree = "<group>"; };
965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UINavigationControllerDelegate.swift"; sourceTree = "<group>"; }; 965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+UINavigationControllerDelegate.swift"; sourceTree = "<group>"; };
965FE9A01FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+CustomTransition.swift"; sourceTree = "<group>"; };
965FE9A21FE4407D0098BDD0 /* MotionTransition+Interactive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MotionTransition+Interactive.swift"; sourceTree = "<group>"; };
96C98DD11E424AB000B22906 /* Motion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Motion.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 96C98DD11E424AB000B22906 /* Motion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Motion.framework; sourceTree = BUILT_PRODUCTS_DIR; };
96E4093D1F24F7370015A2B5 /* MotionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimator.swift; sourceTree = "<group>"; }; 96E4093D1F24F7370015A2B5 /* MotionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimator.swift; sourceTree = "<group>"; };
96E4093E1F24F7370015A2B5 /* MotionAnimatorViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimatorViewContext.swift; sourceTree = "<group>"; }; 96E4093E1F24F7370015A2B5 /* MotionAnimatorViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimatorViewContext.swift; sourceTree = "<group>"; };
...@@ -151,6 +155,8 @@ ...@@ -151,6 +155,8 @@
965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */, 965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */,
965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */, 965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */,
965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */, 965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */,
965FE9A01FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift */,
965FE9A21FE4407D0098BDD0 /* MotionTransition+Interactive.swift */,
); );
path = Transition; path = Transition;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -371,6 +377,7 @@ ...@@ -371,6 +377,7 @@
96E409841F24F7370015A2B5 /* IgnoreSubviewModifiersPreprocessor.swift in Sources */, 96E409841F24F7370015A2B5 /* IgnoreSubviewModifiersPreprocessor.swift in Sources */,
96E409771F24F7370015A2B5 /* MotionAnimationState.swift in Sources */, 96E409771F24F7370015A2B5 /* MotionAnimationState.swift in Sources */,
96E409761F24F7370015A2B5 /* MotionAnimation.swift in Sources */, 96E409761F24F7370015A2B5 /* MotionAnimation.swift in Sources */,
965FE9A31FE4407D0098BDD0 /* MotionTransition+Interactive.swift in Sources */,
96E4096B1F24F7370015A2B5 /* Motion+Array.swift in Sources */, 96E4096B1F24F7370015A2B5 /* Motion+Array.swift in Sources */,
96E409721F24F7370015A2B5 /* Motion+UIViewController.swift in Sources */, 96E409721F24F7370015A2B5 /* Motion+UIViewController.swift in Sources */,
96E4097E1F24F7370015A2B5 /* MotionSnapshotType.swift in Sources */, 96E4097E1F24F7370015A2B5 /* MotionSnapshotType.swift in Sources */,
...@@ -378,6 +385,7 @@ ...@@ -378,6 +385,7 @@
965FE97A1FE1D83D0098BDD0 /* MotionTransition.swift in Sources */, 965FE97A1FE1D83D0098BDD0 /* MotionTransition.swift in Sources */,
965FE98D1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift in Sources */, 965FE98D1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift in Sources */,
96E409871F24F7370015A2B5 /* SourcePreprocessor.swift in Sources */, 96E409871F24F7370015A2B5 /* SourcePreprocessor.swift in Sources */,
965FE9A11FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift in Sources */,
96E409701F24F7370015A2B5 /* Motion+UIKit.swift in Sources */, 96E409701F24F7370015A2B5 /* Motion+UIKit.swift in Sources */,
965FE9771FE0976F0098BDD0 /* ConditionalPreprocessor.swift in Sources */, 965FE9771FE0976F0098BDD0 /* ConditionalPreprocessor.swift in Sources */,
96E4097B1F24F7370015A2B5 /* MotionCoordinateSpace.swift in Sources */, 96E4097B1F24F7370015A2B5 /* MotionCoordinateSpace.swift in Sources */,
......
...@@ -53,18 +53,18 @@ public protocol MotionAnimator: class { ...@@ -53,18 +53,18 @@ public protocol MotionAnimator: class {
/** /**
Moves the view's animation to the given elapsed time. Moves the view's animation to the given elapsed time.
- Parameter to elapsedTime: A TimeInterval. - Parameter to progress: A TimeInterval.
*/ */
func seek(to elapsedTime: TimeInterval) func seek(to progress: TimeInterval)
/** /**
Resumes the animation with a given elapsed time and Resumes the animation with a given elapsed time and
optional reversed boolean. optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval. - Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation - Parameter isReversed: A boolean to reverse the animation
or not. or not.
*/ */
func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval
/** /**
Applies the given state to the given view. Applies the given state to the given view.
......
...@@ -88,21 +88,21 @@ internal class MotionAnimatorViewContext { ...@@ -88,21 +88,21 @@ internal class MotionAnimatorViewContext {
/** /**
Resumes the animation with a given elapsed time and Resumes the animation with a given elapsed time and
optional reversed boolean. optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval. - Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation - Parameter isReversed: A boolean to reverse the animation
or not. or not.
- Returns: A TimeInterval. - Returns: A TimeInterval.
*/ */
@discardableResult @discardableResult
func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
return 0 return 0
} }
/** /**
Moves the animation to the given elapsed time. Moves the animation to the given elapsed time.
- Parameter to elapsedTime: A TimeInterval. - Parameter to progress: A TimeInterval.
*/ */
func seek(to elapsedTime: TimeInterval) {} func seek(to progress: TimeInterval) {}
/** /**
Applies the given state to the target state. Applies the given state to the target state.
......
...@@ -86,26 +86,26 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext { ...@@ -86,26 +86,26 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
} }
} }
override func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { override func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
for (key, (fromValue, toValue)) in state { for (key, (fromValue, toValue)) in state {
state[key] = (currentValue(for: key), isReversed ? fromValue : toValue) state[key] = (currentValue(for: key), isReversed ? fromValue : toValue)
} }
if isReversed { if isReversed {
if elapsedTime > targetState.delay + duration { if progress > targetState.delay + duration {
let backDelay = elapsedTime - (targetState.delay + duration) let backDelay = progress - (targetState.delay + duration)
return animate(delay: backDelay, duration: duration) return animate(delay: backDelay, duration: duration)
} else if elapsedTime > targetState.delay { } else if progress > targetState.delay {
return animate(delay: 0, duration: duration - elapsedTime - targetState.delay) return animate(delay: 0, duration: duration - progress - targetState.delay)
} }
} else { } else {
if elapsedTime <= targetState.delay { if progress <= targetState.delay {
return animate(delay: targetState.delay - elapsedTime, duration: duration) return animate(delay: targetState.delay - progress, duration: duration)
} else if elapsedTime <= targetState.delay + duration { } else if progress <= targetState.delay + duration {
let timePassedDelay = elapsedTime - targetState.delay let timePassedDelay = progress - targetState.delay
return animate(delay: 0, duration: duration - timePassedDelay) return animate(delay: 0, duration: duration - timePassedDelay)
} }
} }
...@@ -113,8 +113,8 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext { ...@@ -113,8 +113,8 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
return 0 return 0
} }
override func seek(to elapsedTime: TimeInterval) { override func seek(to progress: TimeInterval) {
let timeOffset = CGFloat(elapsedTime - targetState.delay) let timeOffset = CGFloat(progress - targetState.delay)
for (layer, key, anim) in animations { for (layer, key, anim) in animations {
anim.speed = 0 anim.speed = 0
......
...@@ -46,9 +46,9 @@ class MotionCoreAnimator: MotionAnimator { ...@@ -46,9 +46,9 @@ class MotionCoreAnimator: MotionAnimator {
return 0 return 0
} }
func seek(to elapsedTime: TimeInterval) {} func seek(to progress: TimeInterval) {}
func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
return 0 return 0
} }
......
...@@ -101,30 +101,30 @@ internal class MotionTargetStateAnimator<T: MotionAnimatorViewContext>: MotionCo ...@@ -101,30 +101,30 @@ internal class MotionTargetStateAnimator<T: MotionAnimatorViewContext>: MotionCo
/** /**
Moves the view's animation to the given elapsed time. Moves the view's animation to the given elapsed time.
- Parameter to elapsedTime: A TimeInterval. - Parameter to progress: A TimeInterval.
*/ */
override func seek(to elapsedTime: TimeInterval) { override func seek(to progress: TimeInterval) {
for v in viewToContexts.values { for v in viewToContexts.values {
v.seek(to: elapsedTime) v.seek(to: progress)
} }
} }
/** /**
Resumes the animation with a given elapsed time and Resumes the animation with a given elapsed time and
optional reversed boolean. optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval. - Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation - Parameter isReversed: A boolean to reverse the animation
or not. or not.
*/ */
override func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { override func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
var duration: TimeInterval = 0 var duration: TimeInterval = 0
for (_, v) in viewToContexts { for (_, v) in viewToContexts {
if nil == v.targetState.duration { if nil == v.targetState.duration {
v.duration = max(v.duration, v.snapshot.optimizedDuration(targetState: v.targetState) + elapsedTime) v.duration = max(v.duration, v.snapshot.optimizedDuration(targetState: v.targetState) + progress)
} }
duration = max(duration, v.resume(at: elapsedTime, isReversed: isReversed)) duration = max(duration, v.resume(at: progress, isReversed: isReversed))
} }
return duration return duration
......
...@@ -43,7 +43,7 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext { ...@@ -43,7 +43,7 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext {
return view is UIVisualEffectView && nil != state.opacity return view is UIVisualEffectView && nil != state.opacity
} }
override func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { override func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
guard let visualEffectView = snapshot as? UIVisualEffectView else { guard let visualEffectView = snapshot as? UIVisualEffectView else {
return 0 return 0
} }
...@@ -65,9 +65,9 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext { ...@@ -65,9 +65,9 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext {
return duration return duration
} }
override func seek(to elapsedTime: TimeInterval) { override func seek(to progress: TimeInterval) {
viewPropertyAnimator?.pauseAnimation() viewPropertyAnimator?.pauseAnimation()
viewPropertyAnimator?.fractionComplete = CGFloat(elapsedTime / duration) viewPropertyAnimator?.fractionComplete = CGFloat(progress / duration)
} }
override func clean() { override func clean() {
......
...@@ -101,9 +101,9 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator { ...@@ -101,9 +101,9 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
This method is called when an interactive animation is in place This method is called when an interactive animation is in place
The plugin should pause the animation, and seek to the given progress The plugin should pause the animation, and seek to the given progress
- Parameters: - Parameters:
- elapsedTime: time of the animation to seek to. - progress: time of the animation to seek to.
*/ */
open func seek(to elapsedTime: TimeInterval) {} open func seek(to progress: TimeInterval) {}
/** /**
For supporting interactive animation only. For supporting interactive animation only.
...@@ -111,10 +111,10 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator { ...@@ -111,10 +111,10 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
This method is called when an interactive animation is ended This method is called when an interactive animation is ended
The plugin should resume the animation. The plugin should resume the animation.
- Parameters: - Parameters:
- elapsedTime: will be the same value since last `seekTo` - progress: will be the same value since last `seekTo`
- reverse: a boolean value indicating whether or not the animation should reverse - reverse: a boolean value indicating whether or not the animation should reverse
*/ */
open func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { return 0 } open func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval { return 0 }
/** /**
For supporting interactive animation only. For supporting interactive animation only.
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
import UIKit import UIKit
protocol MotionProgressRunnerDelegate: class { protocol MotionProgressRunnerDelegate: class {
func update(elapsedTime: TimeInterval) func update(progress: TimeInterval)
func complete(isFinishing: Bool) func complete(isFinishing: Bool)
} }
...@@ -61,7 +61,7 @@ class MotionProgressRunner { ...@@ -61,7 +61,7 @@ class MotionProgressRunner {
return return
} }
delegate?.update(elapsedTime: timePassed / duration) delegate?.update(progress: timePassed / duration)
} }
func start(timePassed: TimeInterval, totalTime: TimeInterval, reverse: Bool) { func start(timePassed: TimeInterval, totalTime: TimeInterval, reverse: Bool) {
......
...@@ -32,7 +32,7 @@ public protocol MotionTargetStateObserver { ...@@ -32,7 +32,7 @@ public protocol MotionTargetStateObserver {
/** /**
Executed when the elapsed time changes during a transition. Executed when the elapsed time changes during a transition.
- Parameter transitionObserver: A MotionTargetStateObserver. - Parameter transitionObserver: A MotionTargetStateObserver.
- Parameter didUpdateWith elapsedTime: A TimeInterval. - Parameter didUpdateWith progress: A TimeInterval.
*/ */
func motion(transitionObserver: MotionTargetStateObserver, didUpdateWith elapsedTime: TimeInterval) func motion(transitionObserver: MotionTargetStateObserver, didUpdateWith progress: TimeInterval)
} }
...@@ -75,13 +75,10 @@ extension MotionTransition { ...@@ -75,13 +75,10 @@ extension MotionTransition {
// We don't want fromView to layout after our animation starts. // We don't want fromView to layout after our animation starts.
// Therefore we kick off the layout beforehand // Therefore we kick off the layout beforehand
fromView?.layoutIfNeeded() fromView?.layoutIfNeeded()
for animator in animators { for animator in animators {
let duration = animator.animate(fromViews: animatingFromViews.filter { let duration = animator.animate(fromViews: animatingFromViews.filter {
print(animator.canAnimate(view: $0, isAppearing: false))
return animator.canAnimate(view: $0, isAppearing: false) return animator.canAnimate(view: $0, isAppearing: false)
}, toViews: animatingToViews.filter { }, toViews: animatingToViews.filter {
print(animator.canAnimate(view: $0, isAppearing: false))
return animator.canAnimate(view: $0, isAppearing: true) return animator.canAnimate(view: $0, isAppearing: true)
}) })
...@@ -99,7 +96,7 @@ extension MotionTransition { ...@@ -99,7 +96,7 @@ extension MotionTransition {
} else if let startingProgress = startingProgress { } else if let startingProgress = startingProgress {
update(startingProgress) update(startingProgress)
} else if animatorWantsInteractive { } else if animatorWantsInteractive {
update(elapsedTime: 0) update(0)
} else { } else {
complete(after: totalDuration, isFinishing: true) complete(after: totalDuration, isFinishing: true)
} }
......
...@@ -45,9 +45,9 @@ extension MotionTransition { ...@@ -45,9 +45,9 @@ extension MotionTransition {
return return
} }
let totalTime = after / (isFinishing ? max((1 - elapsedTime), 0.01) : max(elapsedTime, 0.01)) let totalTime = after / (isFinishing ? max((1 - progress), 0.01) : max(progress, 0.01))
progressRunner.start(timePassed: elapsedTime * totalTime, totalTime: totalTime, reverse: !isFinishing) progressRunner.start(timePassed: progress * totalTime, totalTime: totalTime, reverse: !isFinishing)
} }
/** /**
...@@ -84,7 +84,7 @@ extension MotionTransition { ...@@ -84,7 +84,7 @@ extension MotionTransition {
animators.removeAll() animators.removeAll()
plugins.removeAll() plugins.removeAll()
context = nil context = nil
elapsedTime = 0 progress = 0
totalDuration = 0 totalDuration = 0
state = .possible state = .possible
} }
......
/*
* 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
extension MotionTransition {
/**
A helper transition function.
- Parameter from: A UIViewController.
- Parameter to: A UIViewController.
- Parameter in view: A UIView.
- Parameter completion: An optional completion handler.
*/
public func transition(from: UIViewController, to: UIViewController, in view: UIView, completion: ((Bool) -> Void)? = nil) {
guard !isTransitioning else {
return
}
state = .notified
isPresenting = true
transitionContainer = view
fromViewController = from
toViewController = to
completionCallback = { [weak self] in
guard let `self` = self else {
return
}
completion?($0)
self.state = .possible
}
start()
}
}
/*
* 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
extension MotionTransition {
/**
Updates the elapsed time for the interactive transition.
- Parameter progress t: the current progress, must be between -1...1.
*/
func update(_ percentageComplete: TimeInterval) {
guard .animating == state else {
startingProgress = percentageComplete
return
}
progressRunner.stop()
progress = Double(CGFloat(percentageComplete).clamp(0, 1))
}
/**
Finish the interactive transition.
Will stop the interactive transition and animate from the
current state to the **end** state.
- Parameter isAnimated: A Boolean.
*/
func finish(isAnimated: Bool = true) {
guard .animating == state || .notified == state || .starting == state else {
return
}
guard isAnimated else {
complete(isFinishing: true)
return
}
var d: TimeInterval = 0
for a in animators {
d = max(d, a.resume(at: progress * totalDuration, isReversed: false))
}
complete(after: d, isFinishing: true)
}
/**
Cancel the interactive transition.
Will stop the interactive transition and animate from the
current state to the **begining** state
- Parameter isAnimated: A boolean indicating if the completion is animated.
*/
func cancel(isAnimated: Bool = true) {
guard .animating == state || .notified == state || .starting == state else {
return
}
guard isAnimated else {
complete(isFinishing: false)
return
}
var d: TimeInterval = 0
for a in animators {
var t = progress
if t < 0 {
t = -t
}
d = max(d, a.resume(at: t * totalDuration, isReversed: true))
}
complete(after: d, isFinishing: false)
}
/**
Override transition animations during an interactive animation.
For example:
Motion.shared.apply([.position(x:50, y:50)], to: view)
will set the view's position to 50, 50
- Parameter modifiers: An Array of MotionModifier.
- Parameter to view: A UIView.
*/
func apply(modifiers: [MotionModifier], to view: UIView) {
guard .animating == state else {
return
}
let targetState = MotionTargetState(modifiers: modifiers)
if let otherView = context.pairedView(for: view) {
for animator in animators {
animator.apply(state: targetState, to: otherView)
}
}
for animator in self.animators {
animator.apply(state: targetState, to: view)
}
}
}
...@@ -40,12 +40,27 @@ extension MotionTransition { ...@@ -40,12 +40,27 @@ extension MotionTransition {
prepareViewFrame() prepareViewFrame()
prepareViewControllers() prepareViewControllers()
prepareSnapshotView() prepareSnapshotView()
preparePlugins()
preparePreprocessors() preparePreprocessors()
prepareAnimators() prepareAnimators()
preparePlugins()
for v in plugins {
preprocessors.append(v)
animators.append(v)
}
prepareTransitionContainer() prepareTransitionContainer()
prepareContainer() prepareContainer()
prepareContext() prepareContext()
for v in preprocessors {
v.motion = self
}
for v in animators {
v.motion = self
}
prepareViewHierarchy() prepareViewHierarchy()
prepareAnimatingViews() prepareAnimatingViews()
prepareToView() prepareToView()
...@@ -83,14 +98,10 @@ fileprivate extension MotionTransition { ...@@ -83,14 +98,10 @@ fileprivate extension MotionTransition {
/// Prepares the snapshot view, which hides any flashing that may occur. /// Prepares the snapshot view, which hides any flashing that may occur.
func prepareSnapshotView() { func prepareSnapshotView() {
guard let v = transitionContainer else { fullScreenSnapshot = transitionContainer?.window?.snapshotView(afterScreenUpdates: false) ?? fromView?.snapshotView(afterScreenUpdates: false)
return
}
fullScreenSnapshot = v.window?.snapshotView(afterScreenUpdates: false) ?? fromView?.snapshotView(afterScreenUpdates: false)
if let snapshot = fullScreenSnapshot { if let snapshot = fullScreenSnapshot {
(v.window ?? v)?.addSubview(snapshot) (transitionContainer?.window ?? transitionContainer)?.addSubview(snapshot)
} }
if let v = fromViewController?.motionStoredSnapshot { if let v = fromViewController?.motionStoredSnapshot {
...@@ -104,60 +115,35 @@ fileprivate extension MotionTransition { ...@@ -104,60 +115,35 @@ fileprivate extension MotionTransition {
} }
} }
/// Prepares the plugins.
func preparePlugins() {
plugins = MotionTransition.enabledPlugins.map {
return $0.init()
}
}
/// Prepares the preprocessors. /// Prepares the preprocessors.
func preparePreprocessors() { func preparePreprocessors() {
for x in [IgnoreSubviewTransitionsPreprocessor(), preprocessors = [IgnoreSubviewTransitionsPreprocessor(),
ConditionalPreprocessor(), ConditionalPreprocessor(),
TransitionPreprocessor(), TransitionPreprocessor(),
MatchPreprocessor(), MatchPreprocessor(),
SourcePreprocessor(), SourcePreprocessor(),
CascadePreprocessor()] as [MotionPreprocessor] { CascadePreprocessor()]
preprocessors.append(x)
}
for v in preprocessors {
v.motion = self
}
} }
/// Prepares the animators. /// Prepares the animators.
func prepareAnimators() { func prepareAnimators() {
animators.append(MotionTargetStateAnimator<MotionCoreAnimationViewContext>()) animators = [MotionTargetStateAnimator<MotionCoreAnimationViewContext>()]
if #available(iOS 10, tvOS 10, *) { if #available(iOS 10, tvOS 10, *) {
animators.append(MotionTargetStateAnimator<MotionViewPropertyViewContext>()) animators.append(MotionTargetStateAnimator<MotionViewPropertyViewContext>())
} }
for v in animators {
v.motion = self
}
}
/// Prepares the plugins.
func preparePlugins() {
for x in MotionTransition.enabledPlugins.map({
return $0.init()
}) {
plugins.append(x)
}
for plugin in plugins {
preprocessors.append(plugin)
animators.append(plugin)
}
} }
/// Prepares the transition container. /// Prepares the transition container.
func prepareTransitionContainer() { func prepareTransitionContainer() {
guard let v = transitionContainer else { transitionContainer?.isUserInteractionEnabled = false
return
}
v.isUserInteractionEnabled = false
// a view to hold all the animating views
container = UIView(frame: v.bounds)
v.addSubview(container!)
} }
/// Prepares the view that holds all the animating views. /// Prepares the view that holds all the animating views.
...@@ -193,24 +179,16 @@ fileprivate extension MotionTransition { ...@@ -193,24 +179,16 @@ fileprivate extension MotionTransition {
tv.updateConstraintsIfNeeded() tv.updateConstraintsIfNeeded()
tv.setNeedsLayout() tv.setNeedsLayout()
tv.layoutIfNeeded() tv.layoutIfNeeded()
context.set(fromViews: fv.flattenedViewHierarchy, toViews: tv.flattenedViewHierarchy)
} }
/// Prepares the view hierarchy. /// Prepares the view hierarchy.
func prepareViewHierarchy() { func prepareViewHierarchy() {
guard let fv = fromView else { if (.auto == viewOrderStrategy &&
return
}
guard let tv = toView else {
return
}
context.set(fromViews: fv.flattenedViewHierarchy, toViews: tv.flattenedViewHierarchy)
if (viewOrderStrategy == .auto &&
!isPresenting && !isPresenting &&
!isTabBarController) || !isTabBarController) ||
viewOrderStrategy == .sourceViewOnTop { .sourceViewOnTop == viewOrderStrategy {
context.insertToViewFirst = true context.insertToViewFirst = true
} }
} }
...@@ -226,6 +204,8 @@ fileprivate extension MotionTransition { ...@@ -226,6 +204,8 @@ fileprivate extension MotionTransition {
return false return false
} }
print("FROM PREPARED", animatingFromViews)
animatingToViews = context.toViews.filter { (view) -> Bool in animatingToViews = context.toViews.filter { (view) -> Bool in
for animator in animators { for animator in animators {
if animator.canAnimate(view: view, isAppearing: true) { if animator.canAnimate(view: view, isAppearing: true) {
...@@ -234,6 +214,8 @@ fileprivate extension MotionTransition { ...@@ -234,6 +214,8 @@ fileprivate extension MotionTransition {
} }
return false return false
} }
print("TO PREPARED", animatingFromViews)
} }
/// Prepares the to view. /// Prepares the to view.
......
...@@ -119,7 +119,7 @@ public protocol MotionViewControllerDelegate { ...@@ -119,7 +119,7 @@ public protocol MotionViewControllerDelegate {
#### Use the following methods for controlling the interactive transition: #### Use the following methods for controlling the interactive transition:
```swift ```swift
func update(progress:Double) func update(progress: Double)
func end() func end()
func cancel() func cancel()
func apply(transitions: [MotionTargetState], to view: UIView) func apply(transitions: [MotionTargetState], to view: UIView)
...@@ -348,7 +348,7 @@ open class MotionTransition: NSObject { ...@@ -348,7 +348,7 @@ open class MotionTransition: NSObject {
internal var fullScreenSnapshot: UIView? internal var fullScreenSnapshot: UIView?
/// Progress of the current transition. 0 if no transition is happening. /// Progress of the current transition. 0 if no transition is happening.
public internal(set) var elapsedTime: TimeInterval = 0 { public internal(set) var progress: TimeInterval = 0 {
didSet { didSet {
guard .animating == state else { guard .animating == state else {
return return
...@@ -362,7 +362,7 @@ open class MotionTransition: NSObject { ...@@ -362,7 +362,7 @@ open class MotionTransition: NSObject {
updatePlugins() updatePlugins()
} }
transitionContext?.updateInteractiveTransition(CGFloat(elapsedTime)) transitionContext?.updateInteractiveTransition(CGFloat(progress))
} }
} }
...@@ -418,8 +418,8 @@ open class MotionTransition: NSObject { ...@@ -418,8 +418,8 @@ open class MotionTransition: NSObject {
} }
extension MotionTransition: MotionProgressRunnerDelegate { extension MotionTransition: MotionProgressRunnerDelegate {
func update(elapsedTime: TimeInterval) { func update(progress: TimeInterval) {
self.elapsedTime = elapsedTime self.progress = progress
} }
} }
...@@ -446,13 +446,13 @@ fileprivate extension MotionTransition { ...@@ -446,13 +446,13 @@ fileprivate extension MotionTransition {
} }
for v in observers { for v in observers {
v.motion(transitionObserver: v, didUpdateWith: elapsedTime) v.motion(transitionObserver: v, didUpdateWith: progress)
} }
} }
/// Updates the animators. /// Updates the animators.
func updateAnimators() { func updateAnimators() {
let t = elapsedTime * totalDuration let t = progress * totalDuration
for a in animators { for a in animators {
a.seek(to: t) a.seek(to: t)
} }
...@@ -460,87 +460,13 @@ fileprivate extension MotionTransition { ...@@ -460,87 +460,13 @@ fileprivate extension MotionTransition {
/// Updates the plugins. /// Updates the plugins.
func updatePlugins() { func updatePlugins() {
let t = elapsedTime * totalDuration let t = progress * totalDuration
for p in plugins where p.requirePerFrameCallback { for p in plugins where p.requirePerFrameCallback {
p.seek(to: t) p.seek(to: t)
} }
} }
} }
public extension MotionTransition {
/**
Updates the elapsed time for the interactive transition.
- Parameter elapsedTime t: the current progress, must be between -1...1.
*/
public func update(_ percentageComplete: TimeInterval) {
guard .animating == state else {
startingProgress = percentageComplete
return
}
progressRunner.stop()
elapsedTime = Double(CGFloat(percentageComplete).clamp(0, 1))
}
/**
Cancel the interactive transition.
Will stop the interactive transition and animate from the
current state to the **begining** state
- Parameter isAnimated: A boolean indicating if the completion is animated.
*/
public func cancel(isAnimated: Bool = true) {
guard isTransitioning else {
return
}
guard isAnimated else {
complete(isFinishing: false)
return
}
var d: TimeInterval = 0
for a in animators {
var t = elapsedTime
if t < 0 {
t = -t
}
d = max(d, a.resume(at: t * totalDuration, isReversed: true))
}
complete(after: d, isFinishing: false)
}
/**
Override transition animations during an interactive animation.
For example:
Motion.shared.apply([.position(x:50, y:50)], to: view)
will set the view's position to 50, 50
- Parameter modifiers: An Array of MotionModifier.
- Parameter to view: A UIView.
*/
public func apply(modifiers: [MotionModifier], to view: UIView) {
guard .animating == state else {
return
}
let targetState = MotionTargetState(modifiers: modifiers)
if let otherView = context.pairedView(for: view) {
for animator in animators {
animator.apply(state: targetState, to: otherView)
}
}
for animator in self.animators {
animator.apply(state: targetState, to: view)
}
}
}
internal extension MotionTransition { internal extension MotionTransition {
/** /**
Checks if a given plugin is enabled. Checks if a given plugin is enabled.
...@@ -597,30 +523,6 @@ public extension MotionTransition { ...@@ -597,30 +523,6 @@ public extension MotionTransition {
} }
} }
public extension MotionTransition {
/**
A helper transition function.
- Parameter from: A UIViewController.
- Parameter to: A UIViewController.
- Parameter in view: A UIView.
- Parameter completion: An optional completion handler.
*/
func transition(from: UIViewController, to: UIViewController, in view: UIView, completion: ((Bool) -> Void)? = nil) {
guard !isTransitioning else {
return
}
state = .notified
isPresenting = true
transitionContainer = view
fromViewController = from
toViewController = to
completionCallback = completion
start()
}
}
internal extension MotionTransition { internal extension MotionTransition {
/** /**
Processes the start transition delegation methods. Processes the start transition delegation methods.
......
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