Commit ddf83ac5 by Daniel Dahan

adding MotionTransitionState helper functions

parent 65aef2c1
......@@ -23,13 +23,14 @@
966C53B51EDD327D00A82A57 /* MotionCascadeDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B41EDD327D00A82A57 /* MotionCascadeDirection.swift */; };
966C53B71EDD328F00A82A57 /* MotionCoordinateSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B61EDD328F00A82A57 /* MotionCoordinateSpace.swift */; };
966C53B91EDD366800A82A57 /* MotionTransitionPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B81EDD366800A82A57 /* MotionTransitionPreprocessor.swift */; };
966C53BB1EDD381E00A82A57 /* MotionSubviewPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53BA1EDD381E00A82A57 /* MotionSubviewPreprocessor.swift */; };
966C53BD1EDD396800A82A57 /* MotionAnimationFillMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53BC1EDD396800A82A57 /* MotionAnimationFillMode.swift */; };
966C53BF1EDD399400A82A57 /* MotionAnimationTimingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53BE1EDD399400A82A57 /* MotionAnimationTimingFunction.swift */; };
96BFC1701E63C3460075DE1F /* MotionController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96C98DE31E4382B100B22906 /* MotionController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96C98DE41E4382B100B22906 /* MotionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C98DE31E4382B100B22906 /* MotionController.swift */; };
96C98DE61E43848500B22906 /* MotionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C98DE51E43848500B22906 /* MotionAnimation.swift */; };
96C98DEB1E4389BE00B22906 /* MotionAnimation.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96C98DE51E43848500B22906 /* MotionAnimation.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96E846F41EDDA62F0005F32F /* DefaultMotionTransitionPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E846F31EDDA62F0005F32F /* DefaultMotionTransitionPreprocessor.swift */; };
96E846F61EDDA7F20005F32F /* MotionTransitionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E846F51EDDA7F20005F32F /* MotionTransitionState.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
......@@ -47,7 +48,6 @@
966C53B41EDD327D00A82A57 /* MotionCascadeDirection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionCascadeDirection.swift; sourceTree = "<group>"; };
966C53B61EDD328F00A82A57 /* MotionCoordinateSpace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionCoordinateSpace.swift; sourceTree = "<group>"; };
966C53B81EDD366800A82A57 /* MotionTransitionPreprocessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTransitionPreprocessor.swift; sourceTree = "<group>"; };
966C53BA1EDD381E00A82A57 /* MotionSubviewPreprocessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionSubviewPreprocessor.swift; sourceTree = "<group>"; };
966C53BC1EDD396800A82A57 /* MotionAnimationFillMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimationFillMode.swift; sourceTree = "<group>"; };
966C53BE1EDD399400A82A57 /* MotionAnimationTimingFunction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimationTimingFunction.swift; sourceTree = "<group>"; };
96C98DD11E424AB000B22906 /* Motion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Motion.framework; sourceTree = BUILT_PRODUCTS_DIR; };
......@@ -56,6 +56,8 @@
96C98DE31E4382B100B22906 /* MotionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionController.swift; sourceTree = "<group>"; };
96C98DE51E43848500B22906 /* MotionAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimation.swift; sourceTree = "<group>"; };
96C98DED1E438A5700B22906 /* Motion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Motion.h; sourceTree = "<group>"; };
96E846F31EDDA62F0005F32F /* DefaultMotionTransitionPreprocessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultMotionTransitionPreprocessor.swift; sourceTree = "<group>"; };
96E846F51EDDA7F20005F32F /* MotionTransitionState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTransitionState.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -93,6 +95,7 @@
96C98DED1E438A5700B22906 /* Motion.h */,
964C153C1EDCF6EA00F0869D /* Motion.swift */,
96C98DE31E4382B100B22906 /* MotionController.swift */,
96E846F51EDDA7F20005F32F /* MotionTransitionState.swift */,
9657A6AB1EDA1601004461DE /* MotionObserver.swift */,
9657A6B21EDA63FC004461DE /* MotionContext.swift */,
96C98DE51E43848500B22906 /* MotionAnimation.swift */,
......@@ -113,7 +116,7 @@
isa = PBXGroup;
children = (
966C53B81EDD366800A82A57 /* MotionTransitionPreprocessor.swift */,
966C53BA1EDD381E00A82A57 /* MotionSubviewPreprocessor.swift */,
96E846F31EDDA62F0005F32F /* DefaultMotionTransitionPreprocessor.swift */,
);
name = Preprocessor;
sourceTree = "<group>";
......@@ -223,6 +226,7 @@
files = (
966C53BD1EDD396800A82A57 /* MotionAnimationFillMode.swift in Sources */,
966C53B91EDD366800A82A57 /* MotionTransitionPreprocessor.swift in Sources */,
96E846F41EDDA62F0005F32F /* DefaultMotionTransitionPreprocessor.swift in Sources */,
966C53B71EDD328F00A82A57 /* MotionCoordinateSpace.swift in Sources */,
966C539E1EDD207800A82A57 /* Motion+UIView.swift in Sources */,
966C53B31EDD325B00A82A57 /* MotionSnapshot.swift in Sources */,
......@@ -232,6 +236,7 @@
9657A6B31EDA63FC004461DE /* MotionContext.swift in Sources */,
966C53B51EDD327D00A82A57 /* MotionCascadeDirection.swift in Sources */,
964C15471EDD001A00F0869D /* MotionTransitionAnimation.swift in Sources */,
96E846F61EDDA7F20005F32F /* MotionTransitionState.swift in Sources */,
966C53B11EDD2FE600A82A57 /* Motion+CABasicAnimation.swift in Sources */,
961409AA1E43CF1B00E7BA99 /* Motion+Obj-C.swift in Sources */,
964C153D1EDCF6EA00F0869D /* Motion.swift in Sources */,
......@@ -239,7 +244,6 @@
966C53A01EDD20DA00A82A57 /* Motion+UIViewController.swift in Sources */,
96C98DE41E4382B100B22906 /* MotionController.swift in Sources */,
966C53BF1EDD399400A82A57 /* MotionAnimationTimingFunction.swift in Sources */,
966C53BB1EDD381E00A82A57 /* MotionSubviewPreprocessor.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -30,7 +30,7 @@
import UIKit
public class MotionSubviewPreprocessor: MotionTransitionPreprocessor {
public class DefaultMotionTransitionPreprocessor: MotionTransitionPreprocessor {
/// A reference to a MotionContext.
public weak var context: MotionContext!
......
......@@ -56,6 +56,7 @@ public enum MotionAnimationKeyPath: String {
case height = "bounds.size.height"
case size = "bounds.size"
case shadowPath
case shadowColor
case shadowOffset
case shadowOpacity
case shadowRadius
......@@ -350,12 +351,12 @@ public struct MotionBasicAnimation {
/**
Creates a CABasicaAnimation for the zPosition key path.
- Parameter index: An Int.
- Parameter _ position: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func zPosition(index: Int) -> CABasicAnimation {
public static func zPosition(_ position: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .zPosition)
animation.toValue = NSNumber(integerLiteral: index)
animation.toValue = NSNumber(value: Double(position))
return animation
}
......@@ -404,6 +405,17 @@ public struct MotionBasicAnimation {
}
/**
Creates a CABasicAnimation for the shadowColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func shadow(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the shadowOffset key path.
- Parameter offset: CGSize.
- Returns: A CABasicAnimation.
......
......@@ -278,9 +278,9 @@ extension CALayer {
fade.fromValue = s.value(forKey: MotionAnimationKeyPath.opacity.rawValue) ?? NSNumber(floatLiteral: 1)
a.append(fade)
case let .zPosition(index):
let zPosition = MotionBasicAnimation.zPosition(index: index)
zPosition.fromValue = s.value(forKey: MotionAnimationKeyPath.zPosition.rawValue) ?? NSNumber(integerLiteral: 0)
case let .zPosition(position):
let zPosition = MotionBasicAnimation.zPosition(position)
zPosition.fromValue = s.value(forKey: MotionAnimationKeyPath.zPosition.rawValue) ?? NSNumber(value: 0)
a.append(zPosition)
case .width(_), .height(_), .size(_, _):
......@@ -291,6 +291,9 @@ extension CALayer {
shadowPath.fromValue = s.shadowPath
a.append(shadowPath)
case let .shadowColor(color):
a.append(MotionBasicAnimation.shadow(color: color))
case let .shadowOffset(offset):
let shadowOffset = MotionBasicAnimation.shadow(offset: offset)
shadowOffset.fromValue = s.shadowOffset
......
......@@ -33,6 +33,9 @@ import UIKit
fileprivate var MotionInstanceKey: UInt8 = 0
fileprivate struct MotionInstance {
/// A boolean indicating whether Motion is enabled.
fileprivate var isEnabled: Bool
/// An optional reference to the motion identifier.
fileprivate var identifier: String?
......@@ -45,7 +48,7 @@ extension UIView {
fileprivate var motionInstance: MotionInstance {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceKey) {
return MotionInstance(identifier: nil, animations: nil)
return MotionInstance(isEnabled: true, identifier: nil, animations: nil)
}
}
set(value) {
......@@ -53,7 +56,19 @@ extension UIView {
}
}
/// A boolean that indicates whether motion is enabled.
@IBInspectable
public var isMotionEnabled: Bool {
get {
return motionInstance.isEnabled
}
set(value) {
motionInstance.isEnabled = value
}
}
/// An identifier value used to connect views across UIViewControllers.
@IBInspectable
open var motionIdentifier: String? {
get {
return motionInstance.identifier
......@@ -75,6 +90,21 @@ extension UIView {
}
extension UIView {
/// Retrieves a single Array of UIViews that are in the view hierarchy.
internal var flattenedViewHierarchy: [UIView] {
guard isMotionEnabled else {
return []
}
if #available(iOS 9.0, *) {
return isHidden && (superview is UICollectionView || superview is UIStackView || self is UITableViewCell) ? [] : ([self] + subviews.flatMap { $0.flattenedViewHierarchy })
}
return isHidden && (superview is UICollectionView || self is UITableViewCell) ? [] : ([self] + subviews.flatMap { $0.flattenedViewHierarchy })
}
}
extension UIView {
/**
Snapshots the view instance for animations during transitions.
- Parameter afterUpdates: A boolean indicating whether to snapshot the view
......@@ -83,7 +113,7 @@ extension UIView {
after the snapshot is taken.
- Returns: A UIView instance that is a snapshot of the given UIView.
*/
open func transitionSnapshot(afterUpdates: Bool, shouldHide: Bool = true) -> UIView {
public func transitionSnapshot(afterUpdates: Bool, shouldHide: Bool = true) -> UIView {
isHidden = false
let oldCornerRadius = layer.cornerRadius
......
......@@ -53,23 +53,24 @@ extension UIViewController {
}
}
/// An optional reference to the current snapshot.
internal var motionSnapshot: UIView? {
/// A boolean that indicates whether motion is enabled.
@IBInspectable
public var isMotionEnabled: Bool {
get {
return motionControllerInstance.snapshot
return motionControllerInstance.isEnabled
}
set(value) {
motionControllerInstance.snapshot = value
motionControllerInstance.isEnabled = value
}
}
/// A boolean that indicates whether motion is enabled.
public var isMotionEnabled: Bool {
/// An optional reference to the current snapshot.
internal var motionSnapshot: UIView? {
get {
return motionControllerInstance.isEnabled
return motionControllerInstance.snapshot
}
set(value) {
motionControllerInstance.isEnabled = value
motionControllerInstance.snapshot = value
}
}
}
......@@ -185,6 +185,21 @@ extension Motion {
}
extension Motion {
/**
Removes a snapshot from a given view controller.
- Parameter for viewController: A UIViewController.
*/
fileprivate func removeSnapshot(for viewController: UIViewController?) {
guard let v = viewController?.motionSnapshot else {
return
}
v.removeFromSuperview()
viewController?.motionSnapshot = nil
}
}
extension Motion {
/// Prepares the screen snapshot.
fileprivate func prepareScreenSnapshot() {
screenSnapshot?.removeFromSuperview()
......@@ -194,7 +209,7 @@ extension Motion {
/// Prepares the preprocessors.
fileprivate func preparePreprocessors() {
preprocessors = [MotionSubviewPreprocessor()]
preprocessors = [DefaultMotionTransitionPreprocessor()]
}
/// Prepares the animators.
......@@ -218,7 +233,15 @@ extension Motion {
context = MotionContext(container: container)
container.addSubview(toView)
container.addSubview(fromView)
context.set(fromViews: subviews(of: fromView), toViews: subviews(of: toView))
context.set(fromViews: fromView.flattenedViewHierarchy, toViews: toView.flattenedViewHierarchy)
for v in preprocessors {
v.context = context
}
for v in animators {
v.context = context
}
}
/// Prepares the toView.
......@@ -231,17 +254,11 @@ extension Motion {
}
extension Motion {
/**
Removes a snapshot from a given view controller.
- Parameter for viewController: A UIViewController.
*/
fileprivate func removeSnapshot(for viewController: UIViewController?) {
guard let v = viewController?.motionSnapshot else {
return
/// Iterates through all the processors.
fileprivate func processContext() {
for v in preprocessors {
v.process(fromViews: context.fromViews, toViews: context.toViews)
}
v.removeFromSuperview()
viewController?.motionSnapshot = nil
}
}
......@@ -262,6 +279,8 @@ extension Motion {
prepareContainer()
prepareToView()
prepareContext()
processContext()
}
......
......@@ -62,11 +62,12 @@ public enum MotionAnimation {
case point(x: CGFloat, y: CGFloat)
case position(x: CGFloat, y: CGFloat)
case fade(Double)
case zPosition(Int)
case zPosition(CGFloat)
case width(CGFloat)
case height(CGFloat)
case size(width: CGFloat, height: CGFloat)
case shadowPath(CGPath)
case shadowColor(UIColor)
case shadowOffset(CGSize)
case shadowOpacity(Float)
case shadowRadius(CGFloat)
......
......@@ -44,10 +44,10 @@ open class MotionContext {
fileprivate var snapshotToView = [UIView: UIView]()
/// A reference to the transition from views.
fileprivate var fromViews: [UIView]!
internal var fromViews: [UIView]!
/// A reference to the transition to views.
fileprivate var toViews: [UIView]!
internal var toViews: [UIView]!
/**
An initializer that accepts a given transition container view.
......
......@@ -128,40 +128,6 @@ public class MotionController: NSObject, MotionSubscriber {
extension MotionController {
/**
Populates an Array of UIViews with the subviews of a given view.
- Parameter of view: A UIView.
- Returns: An Array of UIViews.
*/
fileprivate func subviews(of view: UIView, views: inout [UIView]) {
for v in view.subviews {
if nil != v.motionIdentifier {
views.append(v)
}
subviews(of: v, views: &views)
}
}
/**
Retrieves all the subviews of a given view.
- Parameter of view: A UIView.
- Returns: An Array of UIViews.
*/
internal func subviews(of view: UIView) -> [UIView] {
var views: [UIView] = []
subviews(of: view, views: &views)
return views
}
}
extension MotionController {
/// Prepares the transition.
fileprivate func prepareForTransition() {
}
}
extension MotionController {
/**
Handles the animation update for the display link.
- Parameter displayLink: A CADisplayLink.animation
*/
......
......@@ -30,7 +30,7 @@
import UIKit
public protocol MotionTransitionAnimator {
public protocol MotionTransitionAnimator: class {
/// A reference to a MotionContext.
weak var context: MotionContext! { get set }
......
......@@ -30,7 +30,7 @@
import UIKit
public protocol MotionTransitionPreprocessor {
public protocol MotionTransitionPreprocessor: class {
/// A reference to a MotionContext.
weak var context: MotionContext! { get set }
......
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
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