Commit fcf3d822 by Daniel Dahan

initial pass at MotionController rework

parent 19664a2f
......@@ -37,7 +37,7 @@
96AEB6A31EE4610F009A3BE0 /* MotionPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB67D1EE4610F009A3BE0 /* MotionPlugin.swift */; };
96AEB6A41EE4610F009A3BE0 /* MotionStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB67E1EE4610F009A3BE0 /* MotionStringConvertible.swift */; };
96AEB6A51EE4610F009A3BE0 /* MotionTargetState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB67F1EE4610F009A3BE0 /* MotionTargetState.swift */; };
96AEB6A61EE4610F009A3BE0 /* MotionTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6801EE4610F009A3BE0 /* MotionTypes.swift */; };
96AEB6A61EE4610F009A3BE0 /* MotionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6801EE4610F009A3BE0 /* MotionViewController.swift */; };
96AEB6A71EE4610F009A3BE0 /* Lexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6821EE4610F009A3BE0 /* Lexer.swift */; };
96AEB6A81EE4610F009A3BE0 /* Nodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6831EE4610F009A3BE0 /* Nodes.swift */; };
96AEB6A91EE4610F009A3BE0 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6841EE4610F009A3BE0 /* Parser.swift */; };
......@@ -48,6 +48,7 @@
96AEB6AE1EE4610F009A3BE0 /* IgnoreSubviewModifiersPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB68A1EE4610F009A3BE0 /* IgnoreSubviewModifiersPreprocessor.swift */; };
96AEB6AF1EE4610F009A3BE0 /* MatchPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB68B1EE4610F009A3BE0 /* MatchPreprocessor.swift */; };
96AEB6B01EE4610F009A3BE0 /* SourcePreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB68C1EE4610F009A3BE0 /* SourcePreprocessor.swift */; };
96E49A401EEA08F8006D5A93 /* MotionTransitionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E49A3F1EEA08F8006D5A93 /* MotionTransitionObserver.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
......@@ -80,7 +81,7 @@
96AEB67D1EE4610F009A3BE0 /* MotionPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionPlugin.swift; sourceTree = "<group>"; };
96AEB67E1EE4610F009A3BE0 /* MotionStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionStringConvertible.swift; sourceTree = "<group>"; };
96AEB67F1EE4610F009A3BE0 /* MotionTargetState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTargetState.swift; sourceTree = "<group>"; };
96AEB6801EE4610F009A3BE0 /* MotionTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTypes.swift; sourceTree = "<group>"; };
96AEB6801EE4610F009A3BE0 /* MotionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionViewController.swift; sourceTree = "<group>"; };
96AEB6821EE4610F009A3BE0 /* Lexer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lexer.swift; sourceTree = "<group>"; };
96AEB6831EE4610F009A3BE0 /* Nodes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Nodes.swift; sourceTree = "<group>"; };
96AEB6841EE4610F009A3BE0 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; };
......@@ -95,6 +96,7 @@
96C98DDD1E424B9000B22906 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
96C98DE21E43809D00B22906 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
96C98DED1E438A5700B22906 /* Motion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Motion.h; sourceTree = "<group>"; };
96E49A3F1EEA08F8006D5A93 /* MotionTransitionObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTransitionObserver.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -207,7 +209,8 @@
96AEB67D1EE4610F009A3BE0 /* MotionPlugin.swift */,
96AEB67E1EE4610F009A3BE0 /* MotionStringConvertible.swift */,
96AEB67F1EE4610F009A3BE0 /* MotionTargetState.swift */,
96AEB6801EE4610F009A3BE0 /* MotionTypes.swift */,
96AEB6801EE4610F009A3BE0 /* MotionViewController.swift */,
96E49A3F1EEA08F8006D5A93 /* MotionTransitionObserver.swift */,
96AEB6811EE4610F009A3BE0 /* Parser */,
96AEB6861EE4610F009A3BE0 /* Preprocessors */,
);
......@@ -308,9 +311,10 @@
96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */,
96AEB6941EE4610F009A3BE0 /* Motion+Array.swift in Sources */,
96AEB6951EE4610F009A3BE0 /* Motion+CALayer.swift in Sources */,
96AEB6A61EE4610F009A3BE0 /* MotionTypes.swift in Sources */,
96AEB6A61EE4610F009A3BE0 /* MotionViewController.swift in Sources */,
96AEB68E1EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift in Sources */,
96AEB6921EE4610F009A3BE0 /* MotionDebugView.swift in Sources */,
96E49A401EEA08F8006D5A93 /* MotionTransitionObserver.swift in Sources */,
96AEB6A01EE4610F009A3BE0 /* MotionIndependentController.swift in Sources */,
96AEB6AA1EE4610F009A3BE0 /* Regex.swift in Sources */,
96AEB6901EE4610F009A3BE0 /* MotionViewPropertyViewContext.swift in Sources */,
......
......@@ -58,11 +58,13 @@ public class Motion: MotionController {
public internal(set) var isPresenting = true
/// Progress of the current transition, 0 if a transition is not happening.
public override var progress: Double {
public override var elapsedTime: TimeInterval {
didSet {
if isTransitioning {
transitionContext?.updateInteractiveTransition(CGFloat(progress))
guard isTransitioning else {
return
}
transitionContext?.updateInteractiveTransition(CGFloat(elapsedTime))
}
}
......@@ -155,7 +157,7 @@ public extension Motion {
}
}
internal extension Motion {
fileprivate extension Motion {
/// Starts the transition animation.
func start() {
guard isTransitioning else {
......@@ -165,51 +167,25 @@ internal extension Motion {
prepareViewControllers()
prepareSnapshotView()
prepareForTransition()
prepareMotionContext()
prepareContext()
prepareToView()
prepareViewHierarchy()
processContext()
prepareForAnimation()
context.hide(view: toView)
#if os(tvOS)
animate()
#else
if isNavigationController {
// When animating within navigationController, we have to dispatch later into the main queue.
// otherwise snapshots will be pure white. Possibly a bug with UIKit
DispatchQueue.main.async { [weak self] in
self?.animate()
}
} else {
animate()
}
#endif
processForAnimation()
}
}
internal extension Motion {
override func animate() {
context.unhide(view: toView)
if let containerBackgroundColor = containerBackgroundColor {
container.backgroundColor = containerBackgroundColor
} else if !toOverFullScreen && !fromOverFullScreen {
container.backgroundColor = toView.backgroundColor
}
if fromOverFullScreen {
insertToViewFirst = true
}
for animator in animators {
if let animator = animator as? MotionHasInsertOrder {
animator.insertToViewFirst = insertToViewFirst
}
}
updateContainerBackgroundColor()
updateInsertOrder()
super.animate()
fullScreenSnapshot!.removeFromSuperview()
fullScreenSnapshot?.removeFromSuperview()
}
override func complete(finished: Bool) {
......@@ -344,7 +320,7 @@ fileprivate extension Motion {
}
/// Prepares the MotionContext instance.
func prepareMotionContext() {
func prepareContext() {
context.loadViewAlpha(rootView: toView)
context.loadViewAlpha(rootView: fromView)
container.addSubview(toView)
......@@ -370,6 +346,52 @@ internal extension Motion {
super.prepareForTransition()
insert(preprocessor: DefaultAnimationPreprocessor(motion: self), before: DurationPreprocessor.self)
}
override func prepareForAnimation() {
super.prepareForAnimation()
context.hide(view: toView)
}
}
fileprivate extension Motion {
/// Processes the animations.
func processForAnimation() {
#if os(tvOS)
animate()
#else
if isNavigationController {
// When animating within navigationController, we have to dispatch later into the main queue.
// otherwise snapshots will be pure white. Possibly a bug with UIKit
DispatchQueue.main.async { [weak self] in
self?.animate()
}
} else {
animate()
}
#endif
}
}
fileprivate extension Motion {
/// Updates the container background color.
func updateContainerBackgroundColor() {
if let v = containerBackgroundColor {
container.backgroundColor = v
} else if !toOverFullScreen && !fromOverFullScreen {
container.backgroundColor = toView.backgroundColor
}
}
/// Updates the insertToViewFirst boolean for animators.
func updateInsertOrder() {
if fromOverFullScreen {
insertToViewFirst = true
}
for v in animators {
(v as? MotionHasInsertOrder)?.insertToViewFirst = insertToViewFirst
}
}
}
internal extension Motion {
......@@ -418,23 +440,31 @@ internal extension Motion {
}
}
// MARK: UIKit Protocol Conformance
/*****************************
* UIKit protocol extensions *
*****************************/
extension Motion: UIViewControllerAnimatedTransitioning {
/**
The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning.
*/
public func animateTransition(using context: UIViewControllerContextTransitioning) {
guard !isTransitioning else { return }
guard !isTransitioning else {
return
}
transitionContext = context
fromViewController = fromViewController ?? context.viewController(forKey: .from)
toViewController = toViewController ?? context.viewController(forKey: .to)
transitionContainer = context.containerView
start()
}
/**
Returns the transition duration time interval.
- Parameter using transitionContext: An optional UIViewControllerContextTransitioning.
- Returns: A TimeInterval that is the total animation time including delays.
*/
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.375 // doesn't matter, real duration will be calculated later
return 0 // Will be updated dynamically.
}
public func animationEnded(_ transitionCompleted: Bool) {
......@@ -442,11 +472,14 @@ extension Motion: UIViewControllerAnimatedTransitioning {
}
}
extension Motion:UIViewControllerTransitioningDelegate {
var interactiveTransitioning: UIViewControllerInteractiveTransitioning? {
return forceNonInteractive ? nil : self
extension Motion {
/// A reference to the interactive transitioning.
fileprivate var interactiveTransitioning: UIViewControllerInteractiveTransitioning? {
return self
}
}
extension Motion: UIViewControllerTransitioningDelegate {
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresenting = true
self.fromViewController = fromViewController ?? presenting
......@@ -480,7 +513,7 @@ extension Motion: UIViewControllerInteractiveTransitioning {
extension Motion: UINavigationControllerDelegate {
public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.isPresenting = operation == .push
self.isPresenting = .push == operation
self.fromViewController = fromViewController ?? fromVC
self.toViewController = toViewController ?? toVC
self.isNavigationController = true
......@@ -503,12 +536,15 @@ extension Motion: UITabBarControllerDelegate {
public func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isAnimating = true
let fromVCIndex = tabBarController.childViewControllers.index(of: fromVC)!
let toVCIndex = tabBarController.childViewControllers.index(of: toVC)!
self.isPresenting = toVCIndex > fromVCIndex
self.fromViewController = fromViewController ?? fromVC
self.toViewController = toViewController ?? toVC
self.isTabBarController = true
return self
}
}
......
......@@ -28,107 +28,168 @@
import UIKit
/// Base class for managing a Motion transition
public class MotionController: NSObject {
// MARK: Properties
/// context object holding transition informations
/// A reference to the MotionContext.
public internal(set) var context: MotionContext!
/// whether or not we are handling transition interactively
public var interactive: Bool {
return displayLink == nil
/// A boolean indicating whether the transition interactive or not.
public var isInteractive: Bool {
return nil == displayLink
}
/// progress of the current transition. 0 if no transition is happening
public internal(set) var progress: Double = 0 {
/// Progress of the current transition. 0 if no transition is happening.
public internal(set) var elapsedTime: TimeInterval = 0 {
didSet {
if isTransitioning {
if let progressUpdateObservers = progressUpdateObservers {
for observer in progressUpdateObservers {
observer.motionDidUpdateProgress(progress: progress)
}
guard isTransitioning else {
return
}
let elapsedTime = progress * totalDuration
if interactive {
for animator in animators {
animator.seek(to: elapsedTime)
}
} else {
for plugin in plugins where plugin.requirePerFrameCallback {
plugin.seek(to: elapsedTime)
}
}
updateTransitionObservers()
guard isInteractive else {
updatePlugins()
return
}
updateAnimators()
}
}
/// whether or not we are doing a transition
/// A boolean indicating whether a transition is active.
public var isTransitioning: Bool {
return transitionContainer != nil
return nil != transitionContainer
}
/// container we created to hold all animating views, will be a subview of the
/// transitionContainer when isTransitioning
/**
A view container used to hold all the animating views during a
transition.
*/
public internal(set) var container: UIView!
/// this is the container supplied by UIKit
/// UIKit's supplied transition container.
internal var transitionContainer: UIView!
/// An optional completion callback.
internal var completionCallback: ((Bool) -> Void)?
/// Binds the render cycle to the transition animation.
internal var displayLink: CADisplayLink?
internal var progressUpdateObservers: [MotionProgressUpdateObserver]?
/// max duration needed by the default animator and plugins
public internal(set) var totalDuration: TimeInterval = 0.0
/// An Array of observers that are updated during a transition.
internal var transitionObservers: [MotionTransitionObserver]?
/// Max duration used by MotionAnimators and MotionPlugins.
public internal(set) var totalDuration: TimeInterval = 0
/// current animation complete duration.
/// (differs from totalDuration because this one could be the duration for finishing interactive transition)
internal var duration: TimeInterval = 0.0
/// The currently running animation duration.
internal var currentAnimationDuration: TimeInterval = 0
/// The start time of the animation.
internal var beginTime: TimeInterval? {
didSet {
if beginTime != nil {
if displayLink == nil {
displayLink = CADisplayLink(target: self, selector: #selector(displayUpdate(_:)))
displayLink!.add(to: RunLoop.main, forMode: RunLoopMode(rawValue: RunLoopMode.commonModes.rawValue))
}
} else {
guard nil != beginTime else {
displayLink?.isPaused = true
displayLink?.remove(from: RunLoop.main, forMode: RunLoopMode(rawValue: RunLoopMode.commonModes.rawValue))
displayLink = nil
return
}
}
}
func displayUpdate(_ link: CADisplayLink) {
if isTransitioning, duration > 0, let beginTime = beginTime {
let elapsedTime = CACurrentMediaTime() - beginTime
if elapsedTime > duration {
progress = finishing ? 1 : 0
self.beginTime = nil
complete(finished: finishing)
} else {
var completed = elapsedTime / totalDuration
if !finishing {
completed = 1 - completed
}
completed = max(0, min(1, completed))
progress = completed
guard nil == displayLink else {
return
}
displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
displayLink?.add(to: RunLoop.main, forMode: RunLoopMode(rawValue: RunLoopMode.commonModes.rawValue))
}
}
internal var finishing: Bool = true
/// A boolean indicating if the transition has finished.
internal var isFinished = true
/// An Array of MotionPreprocessors used during a transition.
internal var processors: [MotionPreprocessor]!
/// An Array of MotionAnimators used during a transition.
internal var animators: [MotionAnimator]!
/// An Array of MotionPlugins used during a transition.
internal var plugins: [MotionPlugin]!
internal var animatingViews: [(fromViews: [UIView], toViews: [UIView])]!
/// The matching from-views to to-views based on the motionIdentifier value.
internal var transitionPairs: [(fromViews: [UIView], toViews: [UIView])]!
internal static var enabledPlugins: [MotionPlugin.Type] = []
/// Plugins that are enabled during the transition.
internal static var enabledPlugins = [MotionPlugin.Type]()
/// Initializer.
internal override init() {}
}
fileprivate extension MotionController {
/// Updates the transition observers.
func updateTransitionObservers() {
guard let observers = transitionObservers else {
return
}
for v in observers {
v.motion(transitionObserver: v, didUpdateWith: elapsedTime)
}
}
/// Updates the animators.
func updateAnimators() {
let v = elapsedTime * totalDuration
for a in animators {
a.seek(to: v)
}
}
/// Updates the plugins.
func updatePlugins() {
let v = elapsedTime * totalDuration
for p in plugins where p.requirePerFrameCallback {
p.seek(to: v)
}
}
}
fileprivate extension MotionController {
@objc
func handleDisplayLink(_ link: CADisplayLink) {
guard isTransitioning else {
return
}
guard 0 < currentAnimationDuration else {
return
}
guard let t = beginTime else {
return
}
let cTime = CACurrentMediaTime() - t
if cTime > currentAnimationDuration {
elapsedTime = isFinished ? 1 : 0
beginTime = nil
complete(isFinished: isFinished)
} else {
var eTime = cTime / totalDuration
if !isFinished {
eTime = 1 - eTime
}
elapsedTime = max(0, min(1, eTime))
}
}
}
public extension MotionController {
// MARK: Interactive Transition
......@@ -140,7 +201,7 @@ public extension MotionController {
public func update(progress: Double) {
guard isTransitioning else { return }
self.beginTime = nil
self.progress = max(-1, min(1, progress))
self.elapsedTime = max(-1, min(1, progress))
}
/**
......@@ -151,14 +212,14 @@ public extension MotionController {
public func end(animate: Bool = true) {
guard isTransitioning else { return }
if !animate {
self.complete(finished:true)
self.complete(isFinished:true)
return
}
var maxTime: TimeInterval = 0
for animator in self.animators {
maxTime = max(maxTime, animator.resume(at: self.progress * self.totalDuration, isReversed: false))
maxTime = max(maxTime, animator.resume(at: self.elapsedTime * self.totalDuration, isReversed: false))
}
self.complete(after: maxTime, finishing: true)
self.complete(after: maxTime, isFinished: true)
}
/**
......@@ -169,18 +230,18 @@ public extension MotionController {
public func cancel(animate: Bool = true) {
guard isTransitioning else { return }
if !animate {
self.complete(finished:false)
self.complete(isFinished:false)
return
}
var maxTime: TimeInterval = 0
for animator in self.animators {
var adjustedProgress = self.progress
var adjustedProgress = self.elapsedTime
if adjustedProgress < 0 {
adjustedProgress = -adjustedProgress
}
maxTime = max(maxTime, animator.resume(at: adjustedProgress * self.totalDuration, isReversed: true))
}
self.complete(after: maxTime, finishing: false)
self.complete(after: maxTime, isFinished: false)
}
/**
......@@ -219,11 +280,11 @@ public extension MotionController {
- Parameters:
- observer: the observer
*/
func observeForProgressUpdate(observer: MotionProgressUpdateObserver) {
if progressUpdateObservers == nil {
progressUpdateObservers = []
func observeForProgressUpdate(observer: MotionTransitionObserver) {
if transitionObservers == nil {
transitionObservers = []
}
progressUpdateObservers!.append(observer)
transitionObservers!.append(observer)
}
}
......@@ -283,7 +344,7 @@ internal extension MotionController {
func prepareForAnimation() {
guard isTransitioning else { fatalError() }
animatingViews = [([UIView], [UIView])]()
transitionPairs = [([UIView], [UIView])]()
for animator in animators {
let currentFromViews = context.fromViews.filter { (view: UIView) -> Bool in
return animator.canAnimate(view: view, isAppearing: false)
......@@ -291,7 +352,7 @@ internal extension MotionController {
let currentToViews = context.toViews.filter { (view: UIView) -> Bool in
return animator.canAnimate(view: view, isAppearing: true)
}
animatingViews.append((currentFromViews, currentToViews))
transitionPairs.append((currentFromViews, currentToViews))
}
}
......@@ -299,7 +360,7 @@ internal extension MotionController {
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
func animate() {
guard isTransitioning else { fatalError() }
for (currentFromViews, currentToViews) in animatingViews {
for (currentFromViews, currentToViews) in transitionPairs {
// auto hide all animated views
for view in currentFromViews {
context.hide(view: view)
......@@ -312,8 +373,8 @@ internal extension MotionController {
var totalDuration: TimeInterval = 0
var animatorWantsInteractive = false
for (i, animator) in animators.enumerated() {
let duration = animator.animate(fromViews: animatingViews[i].0,
toViews: animatingViews[i].1)
let duration = animator.animate(fromViews: transitionPairs[i].0,
toViews: transitionPairs[i].1)
if duration == .infinity {
animatorWantsInteractive = true
} else {
......@@ -325,23 +386,23 @@ internal extension MotionController {
if animatorWantsInteractive {
update(progress: 0)
} else {
complete(after: totalDuration, finishing: true)
complete(after: totalDuration, isFinished: true)
}
}
func complete(after: TimeInterval, finishing: Bool) {
func complete(after: TimeInterval, isFinished: Bool) {
guard isTransitioning else { fatalError() }
if after <= 0.001 {
complete(finished: finishing)
complete(isFinished: isFinished)
return
}
let elapsedTime = (finishing ? progress : 1 - progress) * totalDuration
self.finishing = finishing
self.duration = after + elapsedTime
self.beginTime = CACurrentMediaTime() - elapsedTime
let v = (isFinished ? elapsedTime : 1 - elapsedTime) * totalDuration
self.isFinished = isFinished
self.currentAnimationDuration = after + v
self.beginTime = CACurrentMediaTime() - v
}
func complete(finished: Bool) {
func complete(isFinished: Bool) {
guard isTransitioning else { fatalError() }
for animator in animators {
animator.clean()
......@@ -351,8 +412,8 @@ internal extension MotionController {
let completion = completionCallback
animatingViews = nil
progressUpdateObservers = nil
transitionPairs = nil
transitionObservers = nil
transitionContainer = nil
completionCallback = nil
container = nil
......@@ -361,10 +422,10 @@ internal extension MotionController {
plugins = nil
context = nil
beginTime = nil
progress = 0
elapsedTime = 0
totalDuration = 0
completion?(finished)
completion?(isFinished)
}
}
......
/*
* 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 Foundation
public protocol MotionTransitionObserver {
/**
Executed when the elapsed time changes during a transition.
- Parameter transitionObserver: A MotionTransitionObserver.
- Parameter didUpdateWith elapsedTime: A TimeInterval.
*/
func motion(transitionObserver: MotionTransitionObserver, didUpdateWith elapsedTime: TimeInterval)
}
......@@ -28,10 +28,6 @@
import UIKit
public protocol MotionProgressUpdateObserver {
func motionDidUpdateProgress(progress: Double)
}
@objc(MotionViewControllerDelegate)
public protocol MotionViewControllerDelegate {
@objc
......
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