Commit 104aead0 by Daniel Dahan

updated MotionTransition extensions before full review

parent 150344a1
......@@ -28,6 +28,8 @@
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 */; };
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 */; };
96E409661F24F7370015A2B5 /* MotionAnimatorViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093E1F24F7370015A2B5 /* MotionAnimatorViewContext.swift */; };
96E409671F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E4093F1F24F7370015A2B5 /* MotionCoreAnimationViewContext.swift */; };
......@@ -104,6 +106,8 @@
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>"; };
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; };
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>"; };
......@@ -151,6 +155,8 @@
965FE98C1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift */,
965FE9901FE43DA60098BDD0 /* MotionTransition+UITabBarControllerDelegate.swift */,
965FE9921FE43DE10098BDD0 /* MotionTransition+UINavigationControllerDelegate.swift */,
965FE9A01FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift */,
965FE9A21FE4407D0098BDD0 /* MotionTransition+Interactive.swift */,
);
path = Transition;
sourceTree = "<group>";
......@@ -371,6 +377,7 @@
96E409841F24F7370015A2B5 /* IgnoreSubviewModifiersPreprocessor.swift in Sources */,
96E409771F24F7370015A2B5 /* MotionAnimationState.swift in Sources */,
96E409761F24F7370015A2B5 /* MotionAnimation.swift in Sources */,
965FE9A31FE4407D0098BDD0 /* MotionTransition+Interactive.swift in Sources */,
96E4096B1F24F7370015A2B5 /* Motion+Array.swift in Sources */,
96E409721F24F7370015A2B5 /* Motion+UIViewController.swift in Sources */,
96E4097E1F24F7370015A2B5 /* MotionSnapshotType.swift in Sources */,
......@@ -378,6 +385,7 @@
965FE97A1FE1D83D0098BDD0 /* MotionTransition.swift in Sources */,
965FE98D1FE334E10098BDD0 /* MotionTransition+UIViewControllerTransitioningDelegate.swift in Sources */,
96E409871F24F7370015A2B5 /* SourcePreprocessor.swift in Sources */,
965FE9A11FE43EF80098BDD0 /* MotionTransition+CustomTransition.swift in Sources */,
96E409701F24F7370015A2B5 /* Motion+UIKit.swift in Sources */,
965FE9771FE0976F0098BDD0 /* ConditionalPreprocessor.swift in Sources */,
96E4097B1F24F7370015A2B5 /* MotionCoordinateSpace.swift in Sources */,
......
......@@ -53,18 +53,18 @@ public protocol MotionAnimator: class {
/**
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
optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval.
- Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation
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.
......
......@@ -88,21 +88,21 @@ internal class MotionAnimatorViewContext {
/**
Resumes the animation with a given elapsed time and
optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval.
- Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation
or not.
- Returns: A TimeInterval.
*/
@discardableResult
func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval {
func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
return 0
}
/**
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.
......
......@@ -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 {
state[key] = (currentValue(for: key), isReversed ? fromValue : toValue)
}
if isReversed {
if elapsedTime > targetState.delay + duration {
let backDelay = elapsedTime - (targetState.delay + duration)
if progress > targetState.delay + duration {
let backDelay = progress - (targetState.delay + duration)
return animate(delay: backDelay, duration: duration)
} else if elapsedTime > targetState.delay {
return animate(delay: 0, duration: duration - elapsedTime - targetState.delay)
} else if progress > targetState.delay {
return animate(delay: 0, duration: duration - progress - targetState.delay)
}
} else {
if elapsedTime <= targetState.delay {
return animate(delay: targetState.delay - elapsedTime, duration: duration)
if progress <= targetState.delay {
return animate(delay: targetState.delay - progress, duration: duration)
} else if elapsedTime <= targetState.delay + duration {
let timePassedDelay = elapsedTime - targetState.delay
} else if progress <= targetState.delay + duration {
let timePassedDelay = progress - targetState.delay
return animate(delay: 0, duration: duration - timePassedDelay)
}
}
......@@ -113,8 +113,8 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
return 0
}
override func seek(to elapsedTime: TimeInterval) {
let timeOffset = CGFloat(elapsedTime - targetState.delay)
override func seek(to progress: TimeInterval) {
let timeOffset = CGFloat(progress - targetState.delay)
for (layer, key, anim) in animations {
anim.speed = 0
......
......@@ -46,9 +46,9 @@ class MotionCoreAnimator: MotionAnimator {
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
}
......
......@@ -101,30 +101,30 @@ internal class MotionTargetStateAnimator<T: MotionAnimatorViewContext>: MotionCo
/**
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 {
v.seek(to: elapsedTime)
v.seek(to: progress)
}
}
/**
Resumes the animation with a given elapsed time and
optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval.
- Parameter at progress: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation
or not.
*/
override func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval {
override func resume(at progress: TimeInterval, isReversed: Bool) -> TimeInterval {
var duration: TimeInterval = 0
for (_, v) in viewToContexts {
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
......
......@@ -43,7 +43,7 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext {
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 {
return 0
}
......@@ -65,9 +65,9 @@ internal class MotionViewPropertyViewContext: MotionAnimatorViewContext {
return duration
}
override func seek(to elapsedTime: TimeInterval) {
override func seek(to progress: TimeInterval) {
viewPropertyAnimator?.pauseAnimation()
viewPropertyAnimator?.fractionComplete = CGFloat(elapsedTime / duration)
viewPropertyAnimator?.fractionComplete = CGFloat(progress / duration)
}
override func clean() {
......
......@@ -101,9 +101,9 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
This method is called when an interactive animation is in place
The plugin should pause the animation, and seek to the given progress
- 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.
......@@ -111,10 +111,10 @@ class MotionPlugin: MotionCorePreprocessor, MotionAnimator {
This method is called when an interactive animation is ended
The plugin should resume the animation.
- 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
*/
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.
......
......@@ -29,7 +29,7 @@
import UIKit
protocol MotionProgressRunnerDelegate: class {
func update(elapsedTime: TimeInterval)
func update(progress: TimeInterval)
func complete(isFinishing: Bool)
}
......@@ -61,7 +61,7 @@ class MotionProgressRunner {
return
}
delegate?.update(elapsedTime: timePassed / duration)
delegate?.update(progress: timePassed / duration)
}
func start(timePassed: TimeInterval, totalTime: TimeInterval, reverse: Bool) {
......
......@@ -32,7 +32,7 @@ public protocol MotionTargetStateObserver {
/**
Executed when the elapsed time changes during a transition.
- 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 {
// We don't want fromView to layout after our animation starts.
// Therefore we kick off the layout beforehand
fromView?.layoutIfNeeded()
for animator in animators {
let duration = animator.animate(fromViews: animatingFromViews.filter {
print(animator.canAnimate(view: $0, isAppearing: false))
return animator.canAnimate(view: $0, isAppearing: false)
}, toViews: animatingToViews.filter {
print(animator.canAnimate(view: $0, isAppearing: false))
return animator.canAnimate(view: $0, isAppearing: true)
})
......@@ -99,7 +96,7 @@ extension MotionTransition {
} else if let startingProgress = startingProgress {
update(startingProgress)
} else if animatorWantsInteractive {
update(elapsedTime: 0)
update(0)
} else {
complete(after: totalDuration, isFinishing: true)
}
......
......@@ -45,9 +45,9 @@ extension MotionTransition {
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 {
animators.removeAll()
plugins.removeAll()
context = nil
elapsedTime = 0
progress = 0
totalDuration = 0
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 {
prepareViewFrame()
prepareViewControllers()
prepareSnapshotView()
preparePlugins()
preparePreprocessors()
prepareAnimators()
preparePlugins()
for v in plugins {
preprocessors.append(v)
animators.append(v)
}
prepareTransitionContainer()
prepareContainer()
prepareContext()
for v in preprocessors {
v.motion = self
}
for v in animators {
v.motion = self
}
prepareViewHierarchy()
prepareAnimatingViews()
prepareToView()
......@@ -83,14 +98,10 @@ fileprivate extension MotionTransition {
/// Prepares the snapshot view, which hides any flashing that may occur.
func prepareSnapshotView() {
guard let v = transitionContainer else {
return
}
fullScreenSnapshot = v.window?.snapshotView(afterScreenUpdates: false) ?? fromView?.snapshotView(afterScreenUpdates: false)
fullScreenSnapshot = transitionContainer?.window?.snapshotView(afterScreenUpdates: false) ?? fromView?.snapshotView(afterScreenUpdates: false)
if let snapshot = fullScreenSnapshot {
(v.window ?? v)?.addSubview(snapshot)
(transitionContainer?.window ?? transitionContainer)?.addSubview(snapshot)
}
if let v = fromViewController?.motionStoredSnapshot {
......@@ -104,60 +115,35 @@ fileprivate extension MotionTransition {
}
}
/// Prepares the plugins.
func preparePlugins() {
plugins = MotionTransition.enabledPlugins.map {
return $0.init()
}
}
/// Prepares the preprocessors.
func preparePreprocessors() {
for x in [IgnoreSubviewTransitionsPreprocessor(),
ConditionalPreprocessor(),
TransitionPreprocessor(),
MatchPreprocessor(),
SourcePreprocessor(),
CascadePreprocessor()] as [MotionPreprocessor] {
preprocessors.append(x)
}
for v in preprocessors {
v.motion = self
}
preprocessors = [IgnoreSubviewTransitionsPreprocessor(),
ConditionalPreprocessor(),
TransitionPreprocessor(),
MatchPreprocessor(),
SourcePreprocessor(),
CascadePreprocessor()]
}
/// Prepares the animators.
func prepareAnimators() {
animators.append(MotionTargetStateAnimator<MotionCoreAnimationViewContext>())
animators = [MotionTargetStateAnimator<MotionCoreAnimationViewContext>()]
if #available(iOS 10, tvOS 10, *) {
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.
func prepareTransitionContainer() {
guard let v = transitionContainer else {
return
}
v.isUserInteractionEnabled = false
// a view to hold all the animating views
container = UIView(frame: v.bounds)
v.addSubview(container!)
transitionContainer?.isUserInteractionEnabled = false
}
/// Prepares the view that holds all the animating views.
......@@ -193,24 +179,16 @@ fileprivate extension MotionTransition {
tv.updateConstraintsIfNeeded()
tv.setNeedsLayout()
tv.layoutIfNeeded()
context.set(fromViews: fv.flattenedViewHierarchy, toViews: tv.flattenedViewHierarchy)
}
/// Prepares the view hierarchy.
func prepareViewHierarchy() {
guard let fv = fromView else {
return
}
guard let tv = toView else {
return
}
context.set(fromViews: fv.flattenedViewHierarchy, toViews: tv.flattenedViewHierarchy)
if (viewOrderStrategy == .auto &&
if (.auto == viewOrderStrategy &&
!isPresenting &&
!isTabBarController) ||
viewOrderStrategy == .sourceViewOnTop {
.sourceViewOnTop == viewOrderStrategy {
context.insertToViewFirst = true
}
}
......@@ -226,6 +204,8 @@ fileprivate extension MotionTransition {
return false
}
print("FROM PREPARED", animatingFromViews)
animatingToViews = context.toViews.filter { (view) -> Bool in
for animator in animators {
if animator.canAnimate(view: view, isAppearing: true) {
......@@ -234,6 +214,8 @@ fileprivate extension MotionTransition {
}
return false
}
print("TO PREPARED", animatingFromViews)
}
/// Prepares the to view.
......
......@@ -119,7 +119,7 @@ public protocol MotionViewControllerDelegate {
#### Use the following methods for controlling the interactive transition:
```swift
func update(progress:Double)
func update(progress: Double)
func end()
func cancel()
func apply(transitions: [MotionTargetState], to view: UIView)
......@@ -348,7 +348,7 @@ open class MotionTransition: NSObject {
internal var fullScreenSnapshot: UIView?
/// 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 {
guard .animating == state else {
return
......@@ -362,7 +362,7 @@ open class MotionTransition: NSObject {
updatePlugins()
}
transitionContext?.updateInteractiveTransition(CGFloat(elapsedTime))
transitionContext?.updateInteractiveTransition(CGFloat(progress))
}
}
......@@ -418,8 +418,8 @@ open class MotionTransition: NSObject {
}
extension MotionTransition: MotionProgressRunnerDelegate {
func update(elapsedTime: TimeInterval) {
self.elapsedTime = elapsedTime
func update(progress: TimeInterval) {
self.progress = progress
}
}
......@@ -446,13 +446,13 @@ fileprivate extension MotionTransition {
}
for v in observers {
v.motion(transitionObserver: v, didUpdateWith: elapsedTime)
v.motion(transitionObserver: v, didUpdateWith: progress)
}
}
/// Updates the animators.
func updateAnimators() {
let t = elapsedTime * totalDuration
let t = progress * totalDuration
for a in animators {
a.seek(to: t)
}
......@@ -460,87 +460,13 @@ fileprivate extension MotionTransition {
/// Updates the plugins.
func updatePlugins() {
let t = elapsedTime * totalDuration
let t = progress * totalDuration
for p in plugins where p.requirePerFrameCallback {
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 {
/**
Checks if a given plugin is enabled.
......@@ -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 {
/**
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