Commit 1bce1231 by Daniel Dahan

reworked MotionDefaultAnimator

parent 2caa4eb1
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
963150D21EE50DA6002B0D42 /* Motion+Obj-C.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */; }; 963150D21EE50DA6002B0D42 /* Motion+Obj-C.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */; };
963150D61EE51C7A002B0D42 /* MotionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D41EE51C7A002B0D42 /* MotionAnimation.swift */; }; 963150D61EE51C7A002B0D42 /* MotionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D41EE51C7A002B0D42 /* MotionAnimation.swift */; };
963150DA1EE51EB4002B0D42 /* MotionAnimationFillMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */; }; 963150DA1EE51EB4002B0D42 /* MotionAnimationFillMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */; };
968989B91EE5B34B003B8F3D /* MotionHasInsertOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 968989B81EE5B34B003B8F3D /* MotionHasInsertOrder.swift */; };
96AEB68D1EE4610F009A3BE0 /* MotionAnimatorViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6651EE4610F009A3BE0 /* MotionAnimatorViewContext.swift */; }; 96AEB68D1EE4610F009A3BE0 /* MotionAnimatorViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6651EE4610F009A3BE0 /* MotionAnimatorViewContext.swift */; };
96AEB68E1EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */; }; 96AEB68E1EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */; };
96AEB68F1EE4610F009A3BE0 /* MotionDefaultAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */; }; 96AEB68F1EE4610F009A3BE0 /* MotionDefaultAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */; };
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+Obj-C.swift"; sourceTree = "<group>"; }; 963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+Obj-C.swift"; sourceTree = "<group>"; };
963150D41EE51C7A002B0D42 /* MotionAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimation.swift; sourceTree = "<group>"; }; 963150D41EE51C7A002B0D42 /* MotionAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimation.swift; sourceTree = "<group>"; };
963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimationFillMode.swift; sourceTree = "<group>"; }; 963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimationFillMode.swift; sourceTree = "<group>"; };
968989B81EE5B34B003B8F3D /* MotionHasInsertOrder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionHasInsertOrder.swift; sourceTree = "<group>"; };
96AEB6651EE4610F009A3BE0 /* MotionAnimatorViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimatorViewContext.swift; sourceTree = "<group>"; }; 96AEB6651EE4610F009A3BE0 /* MotionAnimatorViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimatorViewContext.swift; sourceTree = "<group>"; };
96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionCoreAnimationViewContext.swift; sourceTree = "<group>"; }; 96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionCoreAnimationViewContext.swift; sourceTree = "<group>"; };
96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionDefaultAnimator.swift; sourceTree = "<group>"; }; 96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionDefaultAnimator.swift; sourceTree = "<group>"; };
...@@ -111,6 +113,7 @@ ...@@ -111,6 +113,7 @@
96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */, 96AEB6661EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift */,
96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */, 96AEB6671EE4610F009A3BE0 /* MotionDefaultAnimator.swift */,
96AEB6681EE4610F009A3BE0 /* MotionViewPropertyViewContext.swift */, 96AEB6681EE4610F009A3BE0 /* MotionViewPropertyViewContext.swift */,
968989B81EE5B34B003B8F3D /* MotionHasInsertOrder.swift */,
); );
path = Animator; path = Animator;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -296,6 +299,7 @@ ...@@ -296,6 +299,7 @@
96AEB69D1EE4610F009A3BE0 /* Motion.swift in Sources */, 96AEB69D1EE4610F009A3BE0 /* Motion.swift in Sources */,
963150D61EE51C7A002B0D42 /* MotionAnimation.swift in Sources */, 963150D61EE51C7A002B0D42 /* MotionAnimation.swift in Sources */,
96AEB6A21EE4610F009A3BE0 /* MotionTransition+MotionStringConvertible.swift in Sources */, 96AEB6A21EE4610F009A3BE0 /* MotionTransition+MotionStringConvertible.swift in Sources */,
968989B91EE5B34B003B8F3D /* MotionHasInsertOrder.swift in Sources */,
96AEB6A51EE4610F009A3BE0 /* MotionTargetState.swift in Sources */, 96AEB6A51EE4610F009A3BE0 /* MotionTargetState.swift in Sources */,
96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */, 96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */,
96AEB6941EE4610F009A3BE0 /* Motion+Array.swift in Sources */, 96AEB6941EE4610F009A3BE0 /* Motion+Array.swift in Sources */,
......
...@@ -81,19 +81,13 @@ internal class MotionAnimatorViewContext { ...@@ -81,19 +81,13 @@ internal class MotionAnimatorViewContext {
} }
/** /**
Applies the given state to the target state.
- Parameter state: A MotionTargetState.
*/
func apply(state: MotionTargetState) {}
/**
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 elapsedTime: A TimeInterval. - Parameter at elapsedTime: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation - Parameter isReversed: A boolean to reverse the animation
or not. or not.
*/ */
func resume(elapsedTime: TimeInterval, isReversed: Bool) {} func resume(at elapsedTime: TimeInterval, isReversed: Bool) {}
/** /**
Moves the animation to the given elapsed time. Moves the animation to the given elapsed time.
...@@ -102,6 +96,12 @@ internal class MotionAnimatorViewContext { ...@@ -102,6 +96,12 @@ internal class MotionAnimatorViewContext {
func seek(to elapsedTime: TimeInterval) {} func seek(to elapsedTime: TimeInterval) {}
/** /**
Applies the given state to the target state.
- Parameter state: A MotionTargetState.
*/
func apply(state: MotionTargetState) {}
/**
Starts the animations with an appearing boolean flag. Starts the animations with an appearing boolean flag.
- Parameter isAppearing: A boolean value whether the view - Parameter isAppearing: A boolean value whether the view
is appearing or not. is appearing or not.
......
...@@ -80,7 +80,7 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext { ...@@ -80,7 +80,7 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
} }
} }
override func resume(elapsedTime: TimeInterval, isReversed: Bool) { override func resume(at elapsedTime: TimeInterval, isReversed: Bool) {
for (key, (fromValue, toValue)) in transitionStates { for (key, (fromValue, toValue)) in transitionStates {
transitionStates[key] = (currentValue(for: key), !isReversed ? toValue : fromValue) transitionStates[key] = (currentValue(for: key), !isReversed ? toValue : fromValue)
} }
...@@ -318,7 +318,7 @@ extension MotionCoreAnimationViewContext { ...@@ -318,7 +318,7 @@ extension MotionCoreAnimationViewContext {
} }
/** /**
Constructs a map of key paths to animation values. Constructs a map of key paths to animation state values.
- Parameter targetState state: A MotionTargetState. - Parameter targetState state: A MotionTargetState.
- Returns: A map of key paths to animation values. - Returns: A map of key paths to animation values.
*/ */
......
...@@ -28,93 +28,102 @@ ...@@ -28,93 +28,102 @@
import UIKit import UIKit
internal extension UIView { internal class MotionDefaultAnimator<T: MotionAnimatorViewContext>: MotionAnimator, MotionHasInsertOrder {
func optimizedDuration(fromPosition: CGPoint, toPosition: CGPoint?, size: CGSize?, transform: CATransform3D?) -> TimeInterval { /// A reference to a MotionContext.
let fromPos = fromPosition weak public var context: MotionContext!
let toPos = toPosition ?? fromPos
let fromSize = (layer.presentation() ?? layer).bounds.size /// An index of views to their corresponding animator context.
let toSize = size ?? fromSize var viewToContexts = [UIView: T]()
let fromTransform = (layer.presentation() ?? layer).transform
let toTransform = transform ?? fromTransform var insertToViewFirst = false
let realFromPos = CGPoint.zero.transform(fromTransform) + fromPos
let realToPos = CGPoint.zero.transform(toTransform) + toPos
let realFromSize = fromSize.transform(fromTransform)
let realToSize = toSize.transform(toTransform)
let movePoints = (realFromPos.distance(realToPos) + realFromSize.point.distance(realToSize.point))
// duration is 0.2 @ 0 to 0.375 @ 500
let duration = 0.208 + Double(movePoints.clamp(0, 500)) / 3000
return duration
}
} }
protocol HasInsertOrder: class { extension MotionDefaultAnimator {
var insertToViewFirst: Bool { get set } /**
Animates a given view.
- Parameter view: A UIView.
- Parameter isAppearing: A boolean that determines whether the
view is appearing.
*/
fileprivate func animate(view: UIView, isAppearing: Bool) {
let s = context.snapshotView(for: view)
let v = T(animator: self, snapshot: s, targetState: context[view]!)
viewToContexts[view] = v
v.startAnimations(isAppearing: isAppearing)
}
} }
internal class MotionDefaultAnimator<ViewContext: MotionAnimatorViewContext>: MotionAnimator, HasInsertOrder {
weak public var context: MotionContext!
var viewContexts: [UIView: ViewContext] = [:]
internal var insertToViewFirst = false
public func seekTo(elapsedTime: TimeInterval) { extension MotionDefaultAnimator {
for viewContext in viewContexts.values { func clean() {
viewContext.seek(to: elapsedTime) for v in viewToContexts.values {
v.clean()
}
viewToContexts.removeAll()
insertToViewFirst = false
} }
}
func canAnimate(view: UIView, isAppearing: Bool) -> Bool {
public func resume(elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { guard let state = context[view] else {
var duration: TimeInterval = 0 return false
for (_, context) in viewContexts { }
context.resume(elapsedTime: elapsedTime, isReversed: isReversed)
duration = max(duration, context.duration) return T.canAnimate(view: view, state: state, isAppearing: isAppearing)
} }
return duration
} func animate(fromViews: [UIView], toViews: [UIView]) -> TimeInterval {
var duration: TimeInterval = 0
public func apply(state: MotionTargetState, to view: UIView) {
if let context = viewContexts[view] { if insertToViewFirst {
context.apply(state:state) for v in toViews {
animate(view: v, isAppearing: true)
}
for v in fromViews {
animate(view: v, isAppearing: false)
}
} else {
for v in fromViews {
animate(view: v, isAppearing: false)
}
for v in toViews {
animate(view: v, isAppearing: true)
}
}
for v in viewToContexts.values {
duration = max(duration, v.duration)
}
return duration
} }
}
func seek(to elapsedTime: TimeInterval) {
public func canAnimate(view: UIView, isAppearing: Bool) -> Bool { for v in viewToContexts.values {
guard let state = context[view] else { return false } v.seek(to: elapsedTime)
return ViewContext.canAnimate(view: view, state: state, isAppearing: isAppearing) }
}
public func animate(fromViews: [UIView], toViews: [UIView]) -> TimeInterval {
var duration: TimeInterval = 0
if insertToViewFirst {
for v in toViews { animate(view: v, isAppearing: true) }
for v in fromViews { animate(view: v, isAppearing: false) }
} else {
for v in fromViews { animate(view: v, isAppearing: false) }
for v in toViews { animate(view: v, isAppearing: true) }
} }
for viewContext in viewContexts.values { func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval {
duration = max(duration, viewContext.duration) var duration: TimeInterval = 0
for (_, v) in viewToContexts {
v.resume(at: elapsedTime, isReversed: isReversed)
duration = max(duration, v.duration)
}
return duration
} }
return duration func apply(state: MotionTargetState, to view: UIView) {
} guard let v = viewToContexts[view] else {
return
func animate(view: UIView, isAppearing: Bool) { }
let snapshot = context.snapshotView(for: view)
let viewContext = ViewContext(animator:self, snapshot: snapshot, targetState: context[view]!) v.apply(state: state)
viewContexts[view] = viewContext
viewContext.startAnimations(isAppearing: isAppearing)
}
public func clean() {
for vc in viewContexts.values {
vc.clean()
} }
viewContexts.removeAll()
insertToViewFirst = false
}
} }
/*
* 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.
*/
internal protocol MotionHasInsertOrder: class {
/// A boolean indicating whether to insert the to-view first or not.
var insertToViewFirst: Bool { get set }
}
...@@ -59,7 +59,7 @@ public class MotionDebugPlugin: MotionPlugin { ...@@ -59,7 +59,7 @@ public class MotionDebugPlugin: MotionPlugin {
return .infinity return .infinity
} }
public override func resume(elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { public override func resume(at: TimeInterval, isReversed: Bool) -> TimeInterval {
guard let debugView = debugView else { return 0.4 } guard let debugView = debugView else { return 0.4 }
debugView.delegate = nil debugView.delegate = nil
......
...@@ -28,6 +28,29 @@ ...@@ -28,6 +28,29 @@
import UIKit import UIKit
internal extension UIView {
func optimizedDuration(fromPosition: CGPoint, toPosition: CGPoint?, size: CGSize?, transform: CATransform3D?) -> TimeInterval {
let fromPos = fromPosition
let toPos = toPosition ?? fromPos
let fromSize = (layer.presentation() ?? layer).bounds.size
let toSize = size ?? fromSize
let fromTransform = (layer.presentation() ?? layer).transform
let toTransform = transform ?? fromTransform
let realFromPos = CGPoint.zero.transform(fromTransform) + fromPos
let realToPos = CGPoint.zero.transform(toTransform) + toPos
let realFromSize = fromSize.transform(fromTransform)
let realToSize = toSize.transform(toTransform)
let movePoints = (realFromPos.distance(realToPos) + realFromSize.point.distance(realToSize.point))
// duration is 0.2 @ 0 to 0.375 @ 500
let duration = 0.208 + Double(movePoints.clamp(0, 500)) / 3000
return duration
}
}
public extension UIView { public extension UIView {
private struct AssociatedKeys { private struct AssociatedKeys {
static var motionID = "motionID" static var motionID = "motionID"
......
...@@ -203,7 +203,7 @@ internal extension Motion { ...@@ -203,7 +203,7 @@ internal extension Motion {
insertToViewFirst = true insertToViewFirst = true
} }
for animator in animators { for animator in animators {
if let animator = animator as? HasInsertOrder { if let animator = animator as? MotionHasInsertOrder {
animator.insertToViewFirst = insertToViewFirst animator.insertToViewFirst = insertToViewFirst
} }
} }
......
...@@ -50,11 +50,11 @@ public class MotionController: NSObject { ...@@ -50,11 +50,11 @@ public class MotionController: NSObject {
let elapsedTime = progress * totalDuration let elapsedTime = progress * totalDuration
if interactive { if interactive {
for animator in animators { for animator in animators {
animator.seekTo(elapsedTime: elapsedTime) animator.seek(to: elapsedTime)
} }
} else { } else {
for plugin in plugins where plugin.requirePerFrameCallback { for plugin in plugins where plugin.requirePerFrameCallback {
plugin.seekTo(elapsedTime: elapsedTime) plugin.seek(to: elapsedTime)
} }
} }
} }
...@@ -156,8 +156,7 @@ public extension MotionController { ...@@ -156,8 +156,7 @@ public extension MotionController {
} }
var maxTime: TimeInterval = 0 var maxTime: TimeInterval = 0
for animator in self.animators { for animator in self.animators {
maxTime = max(maxTime, animator.resume(elapsedTime:self.progress * self.totalDuration, maxTime = max(maxTime, animator.resume(at: self.progress * self.totalDuration, isReversed: false))
isReversed: false))
} }
self.complete(after: maxTime, finishing: true) self.complete(after: maxTime, finishing: true)
} }
...@@ -179,8 +178,7 @@ public extension MotionController { ...@@ -179,8 +178,7 @@ public extension MotionController {
if adjustedProgress < 0 { if adjustedProgress < 0 {
adjustedProgress = -adjustedProgress adjustedProgress = -adjustedProgress
} }
maxTime = max(maxTime, animator.resume(elapsedTime:adjustedProgress * self.totalDuration, maxTime = max(maxTime, animator.resume(at: adjustedProgress * self.totalDuration, isReversed: true))
isReversed: true))
} }
self.complete(after: maxTime, finishing: false) self.complete(after: maxTime, finishing: false)
} }
......
...@@ -105,7 +105,7 @@ open class MotionPlugin: NSObject, MotionPreprocessor, MotionAnimator { ...@@ -105,7 +105,7 @@ open class MotionPlugin: NSObject, MotionPreprocessor, MotionAnimator {
- Parameters: - Parameters:
- elapsedTime: time of the animation to seek to. - elapsedTime: time of the animation to seek to.
*/ */
open func seekTo(elapsedTime: TimeInterval) {} open func seek(to elapsedTime: TimeInterval) {}
/** /**
For supporting interactive animation only. For supporting interactive animation only.
...@@ -116,7 +116,7 @@ open class MotionPlugin: NSObject, MotionPreprocessor, MotionAnimator { ...@@ -116,7 +116,7 @@ open class MotionPlugin: NSObject, MotionPreprocessor, MotionAnimator {
- elapsedTime: will be the same value since last `seekTo` - elapsedTime: 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(elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { return 0 } open func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval { return 0 }
/** /**
For supporting interactive animation only. For supporting interactive animation only.
......
...@@ -29,35 +29,86 @@ ...@@ -29,35 +29,86 @@
import UIKit import UIKit
public protocol MotionPreprocessor: class { public protocol MotionPreprocessor: class {
weak var context: MotionContext! { get set } weak var context: MotionContext! { get set }
func process(fromViews: [UIView], toViews: [UIView]) func process(fromViews: [UIView], toViews: [UIView])
} }
public protocol MotionAnimator: class { public protocol MotionAnimator: class {
weak var context: MotionContext! { get set } /// A reference to a MotionContext.
func canAnimate(view: UIView, isAppearing: Bool) -> Bool weak var context: MotionContext! { get set }
func animate(fromViews: [UIView], toViews: [UIView]) -> TimeInterval
func clean() /// Cleans the contexts.
func clean()
func seekTo(elapsedTime: TimeInterval)
func resume(elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval /**
func apply(state: MotionTargetState, to view: UIView) A function that determines if a view can be animated.
- Parameter view: A UIView.
- Parameter isAppearing: A boolean that determines whether the
view is appearing.
*/
func canAnimate(view: UIView, isAppearing: Bool) -> Bool
/**
Animates the from-views to the to-views.
- Parameter fromViews: An Array of UIViews.
- Parameter toViews: An Array of UIViews.
- Returns: A TimeInterval.
*/
func animate(fromViews: [UIView], toViews: [UIView]) -> TimeInterval
/**
Moves the view's animation to the given elapsed time.
- Parameter to elapsedTime: A TimeInterval.
*/
func seek(to elapsedTime: TimeInterval)
/**
Resumes the animation with a given elapsed time and
optional reversed boolean.
- Parameter at elapsedTime: A TimeInterval.
- Parameter isReversed: A boolean to reverse the animation
or not.
*/
func resume(at elapsedTime: TimeInterval, isReversed: Bool) -> TimeInterval
/**
Applies the given state to the given view.
- Parameter state: A MotionTargetState.
- Parameter to view: A UIView.
*/
func apply(state: MotionTargetState, to view: UIView)
} }
public protocol MotionProgressUpdateObserver { public protocol MotionProgressUpdateObserver {
func motionDidUpdateProgress(progress: Double) func motionDidUpdateProgress(progress: Double)
} }
@objc public protocol MotionViewControllerDelegate { @objc(MotionViewControllerDelegate)
@objc optional func motionWillStartAnimatingFrom(viewController: UIViewController) public protocol MotionViewControllerDelegate {
@objc optional func motionDidEndAnimatingFrom(viewController: UIViewController) @objc
@objc optional func motionDidCancelAnimatingFrom(viewController: UIViewController) optional func motionWillStartAnimatingFrom(viewController: UIViewController)
@objc
optional func motionDidEndAnimatingFrom(viewController: UIViewController)
@objc
optional func motionDidCancelAnimatingFrom(viewController: UIViewController)
@objc optional func motionWillStartTransition() @objc
@objc optional func motionDidEndTransition() optional func motionWillStartTransition()
@objc optional func motionDidCancelTransition()
@objc
optional func motionDidEndTransition()
@objc
optional func motionDidCancelTransition()
@objc optional func motionWillStartAnimatingTo(viewController: UIViewController) @objc
@objc optional func motionDidEndAnimatingTo(viewController: UIViewController) optional func motionWillStartAnimatingTo(viewController: UIViewController)
@objc optional func motionDidCancelAnimatingTo(viewController: UIViewController)
@objc
optional func motionDidEndAnimatingTo(viewController: UIViewController)
@objc
optional func motionDidCancelAnimatingTo(viewController: UIViewController)
} }
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