Commit 4976d1e5 by Daniel Dahan

updated file organization

parent d6904f6a
...@@ -11,9 +11,17 @@ ...@@ -11,9 +11,17 @@
961409B61E43D17200E7BA99 /* Motion+Obj-C.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 961409B61E43D17200E7BA99 /* Motion+Obj-C.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961409B81E43D21300E7BA99 /* Motion.h in Headers */ = {isa = PBXBuildFile; fileRef = 96C98DED1E438A5700B22906 /* Motion.h */; settings = {ATTRIBUTES = (Public, ); }; }; 961409B81E43D21300E7BA99 /* Motion.h in Headers */ = {isa = PBXBuildFile; fileRef = 96C98DED1E438A5700B22906 /* Motion.h */; settings = {ATTRIBUTES = (Public, ); }; };
964C153D1EDCF6EA00F0869D /* Motion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964C153C1EDCF6EA00F0869D /* Motion.swift */; }; 964C153D1EDCF6EA00F0869D /* Motion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964C153C1EDCF6EA00F0869D /* Motion.swift */; };
964C15471EDD001A00F0869D /* MotionTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964C15461EDD001A00F0869D /* MotionTransitionAnimation.swift */; };
9657A6AC1EDA1601004461DE /* MotionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6AB1EDA1601004461DE /* MotionObserver.swift */; }; 9657A6AC1EDA1601004461DE /* MotionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6AB1EDA1601004461DE /* MotionObserver.swift */; };
9657A6AE1EDA19D8004461DE /* MotionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */; }; 9657A6AE1EDA19D8004461DE /* MotionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */; };
9657A6B31EDA63FC004461DE /* MotionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6B21EDA63FC004461DE /* MotionContext.swift */; }; 9657A6B31EDA63FC004461DE /* MotionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9657A6B21EDA63FC004461DE /* MotionContext.swift */; };
966C539E1EDD207800A82A57 /* Motion+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C539D1EDD207800A82A57 /* Motion+UIView.swift */; };
966C53A01EDD20DA00A82A57 /* Motion+UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C539F1EDD20DA00A82A57 /* Motion+UIViewController.swift */; };
966C53AF1EDD2F8B00A82A57 /* Motion+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53AE1EDD2F8B00A82A57 /* Motion+CALayer.swift */; };
966C53B11EDD2FE600A82A57 /* Motion+CABasicAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B01EDD2FE600A82A57 /* Motion+CABasicAnimation.swift */; };
966C53B31EDD325B00A82A57 /* MotionSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B21EDD325B00A82A57 /* MotionSnapshot.swift */; };
966C53B51EDD327D00A82A57 /* MotionCascadeDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B41EDD327D00A82A57 /* MotionCascadeDirection.swift */; };
966C53B71EDD328F00A82A57 /* MotionCoordinateSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C53B61EDD328F00A82A57 /* MotionCoordinateSpace.swift */; };
96BFC1701E63C3460075DE1F /* MotionController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96C98DE31E4382B100B22906 /* MotionController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 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 */; }; 96C98DE41E4382B100B22906 /* MotionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C98DE31E4382B100B22906 /* MotionController.swift */; };
96C98DE61E43848500B22906 /* MotionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C98DE51E43848500B22906 /* MotionAnimation.swift */; }; 96C98DE61E43848500B22906 /* MotionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C98DE51E43848500B22906 /* MotionAnimation.swift */; };
...@@ -23,9 +31,17 @@ ...@@ -23,9 +31,17 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+Obj-C.swift"; sourceTree = "<group>"; }; 961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+Obj-C.swift"; sourceTree = "<group>"; };
964C153C1EDCF6EA00F0869D /* Motion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Motion.swift; sourceTree = "<group>"; }; 964C153C1EDCF6EA00F0869D /* Motion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Motion.swift; sourceTree = "<group>"; };
964C15461EDD001A00F0869D /* MotionTransitionAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionTransitionAnimation.swift; sourceTree = "<group>"; };
9657A6AB1EDA1601004461DE /* MotionObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionObserver.swift; sourceTree = "<group>"; }; 9657A6AB1EDA1601004461DE /* MotionObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionObserver.swift; sourceTree = "<group>"; };
9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimator.swift; sourceTree = "<group>"; }; 9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimator.swift; sourceTree = "<group>"; };
9657A6B21EDA63FC004461DE /* MotionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionContext.swift; sourceTree = "<group>"; }; 9657A6B21EDA63FC004461DE /* MotionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionContext.swift; sourceTree = "<group>"; };
966C539D1EDD207800A82A57 /* Motion+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIView.swift"; sourceTree = "<group>"; };
966C539F1EDD20DA00A82A57 /* Motion+UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIViewController.swift"; sourceTree = "<group>"; };
966C53AE1EDD2F8B00A82A57 /* Motion+CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CALayer.swift"; sourceTree = "<group>"; };
966C53B01EDD2FE600A82A57 /* Motion+CABasicAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CABasicAnimation.swift"; sourceTree = "<group>"; };
966C53B21EDD325B00A82A57 /* MotionSnapshot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionSnapshot.swift; sourceTree = "<group>"; };
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>"; };
96C98DD11E424AB000B22906 /* Motion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Motion.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 96C98DD11E424AB000B22906 /* Motion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Motion.framework; sourceTree = BUILT_PRODUCTS_DIR; };
96C98DDD1E424B9000B22906 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 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>"; }; 96C98DE21E43809D00B22906 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
...@@ -67,13 +83,21 @@ ...@@ -67,13 +83,21 @@
96C98DE21E43809D00B22906 /* LICENSE */, 96C98DE21E43809D00B22906 /* LICENSE */,
96C98DDD1E424B9000B22906 /* Info.plist */, 96C98DDD1E424B9000B22906 /* Info.plist */,
96C98DED1E438A5700B22906 /* Motion.h */, 96C98DED1E438A5700B22906 /* Motion.h */,
961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */,
966C539D1EDD207800A82A57 /* Motion+UIView.swift */,
966C539F1EDD20DA00A82A57 /* Motion+UIViewController.swift */,
966C53AE1EDD2F8B00A82A57 /* Motion+CALayer.swift */,
966C53B01EDD2FE600A82A57 /* Motion+CABasicAnimation.swift */,
964C153C1EDCF6EA00F0869D /* Motion.swift */, 964C153C1EDCF6EA00F0869D /* Motion.swift */,
96C98DE31E4382B100B22906 /* MotionController.swift */, 96C98DE31E4382B100B22906 /* MotionController.swift */,
9657A6AB1EDA1601004461DE /* MotionObserver.swift */, 9657A6AB1EDA1601004461DE /* MotionObserver.swift */,
9657A6B21EDA63FC004461DE /* MotionContext.swift */, 9657A6B21EDA63FC004461DE /* MotionContext.swift */,
9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */, 9657A6AD1EDA19D8004461DE /* MotionAnimator.swift */,
96C98DE51E43848500B22906 /* MotionAnimation.swift */, 96C98DE51E43848500B22906 /* MotionAnimation.swift */,
961409A91E43CF1B00E7BA99 /* Motion+Obj-C.swift */, 964C15461EDD001A00F0869D /* MotionTransitionAnimation.swift */,
966C53B21EDD325B00A82A57 /* MotionSnapshot.swift */,
966C53B41EDD327D00A82A57 /* MotionCascadeDirection.swift */,
966C53B61EDD328F00A82A57 /* MotionCoordinateSpace.swift */,
); );
path = Sources; path = Sources;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -161,12 +185,20 @@ ...@@ -161,12 +185,20 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
966C53B71EDD328F00A82A57 /* MotionCoordinateSpace.swift in Sources */,
966C539E1EDD207800A82A57 /* Motion+UIView.swift in Sources */,
966C53B31EDD325B00A82A57 /* MotionSnapshot.swift in Sources */,
96C98DE61E43848500B22906 /* MotionAnimation.swift in Sources */, 96C98DE61E43848500B22906 /* MotionAnimation.swift in Sources */,
9657A6AE1EDA19D8004461DE /* MotionAnimator.swift in Sources */, 9657A6AE1EDA19D8004461DE /* MotionAnimator.swift in Sources */,
9657A6AC1EDA1601004461DE /* MotionObserver.swift in Sources */, 9657A6AC1EDA1601004461DE /* MotionObserver.swift in Sources */,
9657A6B31EDA63FC004461DE /* MotionContext.swift in Sources */, 9657A6B31EDA63FC004461DE /* MotionContext.swift in Sources */,
966C53B51EDD327D00A82A57 /* MotionCascadeDirection.swift in Sources */,
964C15471EDD001A00F0869D /* MotionTransitionAnimation.swift in Sources */,
966C53B11EDD2FE600A82A57 /* Motion+CABasicAnimation.swift in Sources */,
961409AA1E43CF1B00E7BA99 /* Motion+Obj-C.swift in Sources */, 961409AA1E43CF1B00E7BA99 /* Motion+Obj-C.swift in Sources */,
964C153D1EDCF6EA00F0869D /* Motion.swift in Sources */, 964C153D1EDCF6EA00F0869D /* Motion.swift in Sources */,
966C53AF1EDD2F8B00A82A57 /* Motion+CALayer.swift in Sources */,
966C53A01EDD20DA00A82A57 /* Motion+UIViewController.swift in Sources */,
96C98DE41E4382B100B22906 /* MotionController.swift in Sources */, 96C98DE41E4382B100B22906 /* MotionController.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
......
/*
* 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
public enum MotionAnimationKeyPath: String {
case backgroundColor
case barTintColor
case borderColor
case borderWidth
case cornerRadius
case transform
case rotation = "transform.rotation"
case rotationX = "transform.rotation.x"
case rotationY = "transform.rotation.y"
case rotationZ = "transform.rotation.z"
case scale = "transform.scale"
case scaleX = "transform.scale.x"
case scaleY = "transform.scale.y"
case scaleZ = "transform.scale.z"
case translation = "transform.translation"
case translationX = "transform.translation.x"
case translationY = "transform.translation.y"
case translationZ = "transform.translation.z"
case position
case opacity
case zPosition
case width = "bounds.size.width"
case height = "bounds.size.height"
case size = "bounds.size"
case shadowPath
case shadowOffset
case shadowOpacity
case shadowRadius
}
extension CABasicAnimation {
/**
A convenience initializer that takes a given MotionAnimationKeyPath.
- Parameter keyPath: An MotionAnimationKeyPath.
*/
public convenience init(keyPath: MotionAnimationKeyPath) {
self.init(keyPath: keyPath.rawValue)
}
}
public struct MotionBasicAnimation {
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func background(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .backgroundColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the barTintColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func barTint(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .barTintColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the borderColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func border(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .borderColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the borderWidth key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func border(width: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .borderWidth)
animation.toValue = width
return animation
}
/**
Creates a CABasicAnimation for the cornerRadius key path.
- Parameter radius: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func corner(radius: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .cornerRadius)
animation.toValue = radius
return animation
}
/**
Creates a CABasicAnimation for the transform key path.
- Parameter transform: A CATransform3D object.
- Returns: A CABasicAnimation.
*/
public static func transform(transform: CATransform3D) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .transform)
animation.toValue = NSValue(caTransform3D: transform)
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotation(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotation)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationX(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationX)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationY(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationY)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationZ(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationZ)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spin(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotation)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinX(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationX)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinY(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationY)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinZ(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationZ)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scale(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scale)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.x key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleX(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleX)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.y key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleY(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleY)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.z key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleZ(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleZ)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation key path.
- Parameter point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public static func translate(to point: CGPoint) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translation)
animation.toValue = NSValue(cgPoint: point)
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.x key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateX(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationX)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.y key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateY(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationY)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.z key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateZ(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationZ)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func position(x: CGFloat, y: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: CGPoint(x: x, y: y))
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter to point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public static func position(to point: CGPoint) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: point)
return animation
}
/**
Creates a CABasicAnimation for the opacity key path.
- Parameter opacity: A Double.
- Returns: A CABasicAnimation.
*/
public static func fade(opacity: Double) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .opacity)
animation.toValue = NSNumber(floatLiteral: opacity)
return animation
}
/**
Creates a CABasicaAnimation for the zPosition key path.
- Parameter index: An Int.
- Returns: A CABasicAnimation.
*/
public static func zPosition(index: Int) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .zPosition)
animation.toValue = NSNumber(integerLiteral: index)
return animation
}
/**
Creates a CABasicaAnimation for the width key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func width(_ width: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .width)
animation.toValue = NSNumber(floatLiteral: Double(width))
return animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter height: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func height(_ height: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .height)
animation.toValue = NSNumber(floatLiteral: Double(height))
return animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter size: A CGSize.
- Returns: A CABasicAnimation.
*/
public static func size(_ size: CGSize) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .size)
animation.toValue = NSValue(cgSize: size)
return animation
}
/**
Creates a CABasicAnimation for the shadowPath key path.
- Parameter path: A CGPath.
- Returns: A CABasicAnimation.
*/
public static func shadow(path: CGPath) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowPath)
animation.toValue = path
return animation
}
/**
Creates a CABasicAnimation for the shadowOffset key path.
- Parameter offset: CGSize.
- Returns: A CABasicAnimation.
*/
public static func shadow(offset: CGSize) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowOffset)
animation.toValue = NSValue(cgSize: offset)
return animation
}
/**
Creates a CABasicAnimation for the shadowOpacity key path.
- Parameter opacity: Float.
- Returns: A CABasicAnimation.
*/
public static func shadow(opacity: Float) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowOpacity)
animation.toValue = NSNumber(floatLiteral: Double(opacity))
return animation
}
/**
Creates a CABasicAnimation for the shadowRadius key path.
- Parameter radius: CGFloat.
- Returns: A CABasicAnimation.
*/
public static func shadow(radius: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowRadius)
animation.toValue = NSNumber(floatLiteral: Double(radius))
return animation
}
}
/*
* 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
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
extension CALayer {
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open func animate(_ animations: CAAnimation...) {
animate(animations)
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open func animate(_ animations: [CAAnimation]) {
for animation in animations {
if nil == animation.delegate {
animation.delegate = self
}
if let a = animation as? CABasicAnimation {
a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!)
}
if let a = animation as? CAPropertyAnimation {
add(a, forKey: a.keyPath!)
} else if let a = animation as? CAAnimationGroup {
add(a, forKey: nil)
} else if let a = animation as? CATransition {
add(a, forKey: kCATransition)
}
}
}
open func animationDidStart(_ anim: CAAnimation) {}
/**
A delegation function that is executed when the backing layer stops
running an animation.
- Parameter animation: The CAAnimation instance that stopped running.
- Parameter flag: A boolean that indicates if the animation stopped
because it was completed or interrupted. True if completed, false
if interrupted.
*/
open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
guard let a = anim as? CAPropertyAnimation else {
if let a = (anim as? CAAnimationGroup)?.animations {
for x in a {
animationDidStop(x, finished: true)
}
}
return
}
guard let b = a as? CABasicAnimation else {
return
}
guard let v = b.toValue else {
return
}
guard let k = b.keyPath else {
return
}
setValue(v, forKeyPath: k)
removeAnimation(forKey: k)
}
/**
A function that accepts a list of MotionAnimation values and executes them.
- Parameter animations: A list of MotionAnimation values.
*/
open func motion(_ animations: MotionAnimation...) {
motion(animations)
}
/**
A function that accepts an Array of MotionAnimation values and executes them.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open func motion(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
motion(delay: 0, duration: 0.35, timingFunction: .easeInEaseOut, animations: animations, completion: completion)
}
/**
A function that executes an Array of MotionAnimation values.
- Parameter delay: The animation delay TimeInterval.
- Parameter duration: The animation duration TimeInterval.
- Parameter timingFunction: The animation MotionAnimationTimingFunction.
- Parameter animations: An Array of MotionAnimations.
- Parameter completion: An optional completion block.
*/
fileprivate func motion(delay: TimeInterval, duration: TimeInterval, timingFunction: MotionAnimationTimingFunction, animations: [MotionAnimation], completion: (() -> Void)? = nil) {
var t = delay
for v in animations {
switch v {
case let .delay(time):
t = time
default:break
}
}
Motion.delay(t) { [weak self] in
guard let s = self else {
return
}
var a = [CABasicAnimation]()
var tf = timingFunction
var d = duration
var w: CGFloat = s.bounds.width
var h: CGFloat = s.bounds.height
for v in animations {
switch v {
case let .width(width):
w = width
case let .height(height):
h = height
case let .size(width, height):
w = width
h = height
default:break
}
}
var px: CGFloat = s.position.x
var py: CGFloat = s.position.y
for v in animations {
switch v {
case let .x(x):
px = x + w / 2
case let .y(y):
py = y + h / 2
case let .point(x, y):
px = x + w / 2
py = y + h / 2
default:break
}
}
for v in animations {
switch v {
case let .timingFunction(timingFunction):
tf = timingFunction
case let .duration(duration):
d = duration
case let .custom(animation):
a.append(animation)
case let .backgroundColor(color):
a.append(MotionBasicAnimation.background(color: color))
case let .barTintColor(color):
a.append(MotionBasicAnimation.barTint(color: color))
case let .borderColor(color):
a.append(MotionBasicAnimation.border(color: color))
case let .borderWidth(width):
a.append(MotionBasicAnimation.border(width: width))
case let .cornerRadius(radius):
a.append(MotionBasicAnimation.corner(radius: radius))
case let .transform(transform):
a.append(MotionBasicAnimation.transform(transform: transform))
case let .rotationAngle(angle):
let rotate = MotionBasicAnimation.rotation(angle: angle)
a.append(rotate)
case let .rotationAngleX(angle):
a.append(MotionBasicAnimation.rotationX(angle: angle))
case let .rotationAngleY(angle):
a.append(MotionBasicAnimation.rotationY(angle: angle))
case let .rotationAngleZ(angle):
a.append(MotionBasicAnimation.rotationZ(angle: angle))
case let .spin(rotations):
a.append(MotionBasicAnimation.spin(rotations: rotations))
case let .spinX(rotations):
a.append(MotionBasicAnimation.spinX(rotations: rotations))
case let .spinY(rotations):
a.append(MotionBasicAnimation.spinY(rotations: rotations))
case let .spinZ(rotations):
a.append(MotionBasicAnimation.spinZ(rotations: rotations))
case let .scale(to):
a.append(MotionBasicAnimation.scale(to: to))
case let .scaleX(to):
a.append(MotionBasicAnimation.scaleX(to: to))
case let .scaleY(to):
a.append(MotionBasicAnimation.scaleY(to: to))
case let .scaleZ(to):
a.append(MotionBasicAnimation.scaleZ(to: to))
case let .translate(x, y):
a.append(MotionBasicAnimation.translate(to: CGPoint(x: x, y: y)))
case let .translateX(to):
a.append(MotionBasicAnimation.translateX(to: to))
case let .translateY(to):
a.append(MotionBasicAnimation.translateY(to: to))
case let .translateZ(to):
a.append(MotionBasicAnimation.translateZ(to: to))
case .x(_), .y(_), .point(_, _):
let position = MotionBasicAnimation.position(to: CGPoint(x: px, y: py))
a.append(position)
case let .position(x, y):
a.append(MotionBasicAnimation.position(to: CGPoint(x: x, y: y)))
case let .fade(opacity):
let fade = MotionBasicAnimation.fade(opacity: opacity)
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)
a.append(zPosition)
case .width(_), .height(_), .size(_, _):
a.append(MotionBasicAnimation.size(CGSize(width: w, height: h)))
case let .shadowPath(path):
let shadowPath = MotionBasicAnimation.shadow(path: path)
shadowPath.fromValue = s.shadowPath
a.append(shadowPath)
case let .shadowOffset(offset):
let shadowOffset = MotionBasicAnimation.shadow(offset: offset)
shadowOffset.fromValue = s.shadowOffset
a.append(shadowOffset)
case let .shadowOpacity(opacity):
let shadowOpacity = MotionBasicAnimation.shadow(opacity: opacity)
shadowOpacity.fromValue = s.shadowOpacity
a.append(shadowOpacity)
case let .shadowRadius(radius):
let shadowRadius = MotionBasicAnimation.shadow(radius: radius)
shadowRadius.fromValue = s.shadowRadius
a.append(shadowRadius)
case let .depth(offset, opacity, radius):
if let path = s.shadowPath {
let shadowPath = MotionBasicAnimation.shadow(path: path)
shadowPath.fromValue = s.shadowPath
a.append(shadowPath)
}
let shadowOffset = MotionBasicAnimation.shadow(offset: offset)
shadowOffset.fromValue = s.shadowOffset
a.append(shadowOffset)
let shadowOpacity = MotionBasicAnimation.shadow(opacity: opacity)
shadowOpacity.fromValue = s.shadowOpacity
a.append(shadowOpacity)
let shadowRadius = MotionBasicAnimation.shadow(radius: radius)
shadowRadius.fromValue = s.shadowRadius
a.append(shadowRadius)
default:break
}
}
let g = Motion.animate(group: a, duration: d)
g.fillMode = MotionAnimationFillModeToValue(mode: .forwards)
g.isRemovedOnCompletion = false
g.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: tf)
s.animate(g)
guard let execute = completion else {
return
}
Motion.delay(d, execute: execute)
}
}
}
/*
* 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
fileprivate var MotionInstanceKey: UInt8 = 0
fileprivate struct MotionInstance {
/// An optional reference to the motion identifier.
fileprivate var identifier: String?
/// An optional reference to the motion animations.
fileprivate var animations: [MotionAnimation]?
}
extension UIView {
/// MotionInstance reference.
fileprivate var motionInstance: MotionInstance {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceKey) {
return MotionInstance(identifier: nil, animations: nil)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceKey, value: value)
}
}
/// An identifier value used to connect views across UIViewControllers.
open var motionIdentifier: String? {
get {
return motionInstance.identifier
}
set(value) {
motionInstance.identifier = value
}
}
/// The animations to run while in transition.
open var motionAnimations: [MotionAnimation]? {
get {
return motionInstance.animations
}
set(value) {
motionInstance.animations = value
}
}
}
extension UIView {
/**
Snapshots the view instance for animations during transitions.
- Parameter afterUpdates: A boolean indicating whether to snapshot the view
after a render update, or as is.
- Parameter shouldHide: A boolean indicating whether the view should be hidden
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 {
isHidden = false
let oldCornerRadius = layer.cornerRadius
layer.cornerRadius = 0
var oldBackgroundColor: UIColor?
if shouldHide {
oldBackgroundColor = backgroundColor
backgroundColor = .clear
}
let oldTransform = motionTransform
motionTransform = CATransform3DIdentity
let v = snapshotView(afterScreenUpdates: afterUpdates)!
layer.cornerRadius = oldCornerRadius
if shouldHide {
backgroundColor = oldBackgroundColor
}
motionTransform = oldTransform
let contentView = v.subviews.first!
contentView.layer.cornerRadius = layer.cornerRadius
contentView.layer.masksToBounds = true
v.motionIdentifier = motionIdentifier
v.layer.position = motionPosition
v.bounds = bounds
v.layer.cornerRadius = layer.cornerRadius
v.layer.zPosition = layer.zPosition
v.layer.opacity = layer.opacity
v.isOpaque = isOpaque
v.layer.anchorPoint = layer.anchorPoint
v.layer.masksToBounds = layer.masksToBounds
v.layer.borderColor = layer.borderColor
v.layer.borderWidth = layer.borderWidth
v.layer.shadowRadius = layer.shadowRadius
v.layer.shadowOpacity = layer.shadowOpacity
v.layer.shadowColor = layer.shadowColor
v.layer.shadowOffset = layer.shadowOffset
v.contentMode = contentMode
v.motionTransform = motionTransform
v.backgroundColor = backgroundColor
isHidden = shouldHide
return v
}
}
extension UIView {
/// Computes the rotation of the view.
open var motionRotationAngle: CGFloat {
get {
return CGFloat(atan2f(Float(transform.b), Float(transform.a))) * 180 / CGFloat(Double.pi)
}
set(value) {
transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi) * value / 180)
}
}
/// The global position of a view.
open var motionPosition: CGPoint {
return superview?.convert(layer.position, to: nil) ?? layer.position
}
/// The layer.transform of a view.
open var motionTransform: CATransform3D {
get {
return layer.transform
}
set(value) {
layer.transform = value
}
}
/// Computes the scale X axis value of the view.
open var motionScaleX: CGFloat {
return transform.a
}
/// Computes the scale Y axis value of the view.
open var motionScaleY: CGFloat {
return transform.b
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animations: A list of CAAnimations.
*/
open func animate(_ animations: CAAnimation...) {
layer.animate(animations)
}
/**
A function that accepts an Array of CAAnimation objects and executes
them on the view's backing layer.
- Parameter animations: An Array of CAAnimations.
*/
open func animate(_ animations: [CAAnimation]) {
layer.animate(animations)
}
/**
A function that accepts a list of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: A list of MotionAnimation values.
*/
open func motion(_ animations: MotionAnimation...) {
layer.motion(animations)
}
/**
A function that accepts an Array of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open func motion(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
layer.motion(animations, completion: completion)
}
}
/*
* 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
fileprivate var MotionInstanceControllerKey: UInt8 = 0
fileprivate struct MotionInstanceController {
/// A boolean indicating whether Motion is enabled.
fileprivate var isMotionEnabled: Bool
}
extension UIViewController {
/// MotionInstanceController reference.
fileprivate var motionControllerInstance: MotionInstanceController {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceControllerKey) {
return MotionInstanceController(isMotionEnabled: false)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceControllerKey, value: value)
}
}
/// A boolean that indicates whether motion is enabled.
open var isMotionEnabled: Bool {
get {
return motionControllerInstance.isMotionEnabled
}
set(value) {
motionControllerInstance.isMotionEnabled = value
}
}
}
...@@ -86,143 +86,6 @@ public func MotionAnimationTimingFunctionToValue(timingFunction: MotionAnimation ...@@ -86,143 +86,6 @@ public func MotionAnimationTimingFunctionToValue(timingFunction: MotionAnimation
public typealias MotionDelayCancelBlock = (Bool) -> Void public typealias MotionDelayCancelBlock = (Bool) -> Void
fileprivate var MotionInstanceKey: UInt8 = 0
fileprivate var MotionInstanceControllerKey: UInt8 = 0
fileprivate struct MotionInstance {
/// An optional reference to the motion identifier.
fileprivate var identifier: String?
/// An optional reference to the motion animations.
fileprivate var animations: [MotionAnimation]?
}
fileprivate struct MotionInstanceController {
/// A boolean indicating whether Motion is enabled.
fileprivate var isMotionEnabled: Bool
}
extension UIViewController {
/// MotionInstanceController reference.
fileprivate var motionControllerInstance: MotionInstanceController {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceControllerKey) {
return MotionInstanceController(isMotionEnabled: false)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceControllerKey, value: value)
}
}
/// A boolean that indicates whether motion is enabled.
open var isMotionEnabled: Bool {
get {
return motionControllerInstance.isMotionEnabled
}
set(value) {
motionControllerInstance.isMotionEnabled = value
}
}
}
extension UIView {
/// MotionInstance reference.
fileprivate var motionInstance: MotionInstance {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceKey) {
return MotionInstance(identifier: nil, animations: nil)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceKey, value: value)
}
}
/// An identifier value used to connect views across UIViewControllers.
open var motionIdentifier: String? {
get {
return motionInstance.identifier
}
set(value) {
motionInstance.identifier = value
}
}
/// The animations to run while in transition.
open var motionAnimations: [MotionAnimation]? {
get {
return motionInstance.animations
}
set(value) {
motionInstance.animations = value
}
}
}
extension UIView {
/**
Snapshots the view instance for animations during transitions.
- Parameter afterUpdates: A boolean indicating whether to snapshot the view
after a render update, or as is.
- Parameter shouldHide: A boolean indicating whether the view should be hidden
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 {
isHidden = false
let oldCornerRadius = layer.cornerRadius
layer.cornerRadius = 0
var oldBackgroundColor: UIColor?
if shouldHide {
oldBackgroundColor = backgroundColor
backgroundColor = .clear
}
let oldTransform = motionTransform
motionTransform = CATransform3DIdentity
let v = snapshotView(afterScreenUpdates: afterUpdates)!
layer.cornerRadius = oldCornerRadius
if shouldHide {
backgroundColor = oldBackgroundColor
}
motionTransform = oldTransform
let contentView = v.subviews.first!
contentView.layer.cornerRadius = layer.cornerRadius
contentView.layer.masksToBounds = true
v.motionIdentifier = motionIdentifier
v.layer.position = motionPosition
v.bounds = bounds
v.layer.cornerRadius = layer.cornerRadius
v.layer.zPosition = layer.zPosition
v.layer.opacity = layer.opacity
v.isOpaque = isOpaque
v.layer.anchorPoint = layer.anchorPoint
v.layer.masksToBounds = layer.masksToBounds
v.layer.borderColor = layer.borderColor
v.layer.borderWidth = layer.borderWidth
v.layer.shadowRadius = layer.shadowRadius
v.layer.shadowOpacity = layer.shadowOpacity
v.layer.shadowColor = layer.shadowColor
v.layer.shadowOffset = layer.shadowOffset
v.contentMode = contentMode
v.motionTransform = motionTransform
v.backgroundColor = backgroundColor
isHidden = shouldHide
return v
}
}
open class Motion { open class Motion {
/** /**
Executes a block of code after a time delay. Executes a block of code after a time delay.
......
...@@ -30,37 +30,6 @@ ...@@ -30,37 +30,6 @@
import UIKit import UIKit
public enum MotionAnimationKeyPath: String {
case backgroundColor
case barTintColor
case borderColor
case borderWidth
case cornerRadius
case transform
case rotation = "transform.rotation"
case rotationX = "transform.rotation.x"
case rotationY = "transform.rotation.y"
case rotationZ = "transform.rotation.z"
case scale = "transform.scale"
case scaleX = "transform.scale.x"
case scaleY = "transform.scale.y"
case scaleZ = "transform.scale.z"
case translation = "transform.translation"
case translationX = "transform.translation.x"
case translationY = "transform.translation.y"
case translationZ = "transform.translation.z"
case position
case opacity
case zPosition
case width = "bounds.size.width"
case height = "bounds.size.height"
case size = "bounds.size"
case shadowPath
case shadowOffset
case shadowOpacity
case shadowRadius
}
public enum MotionAnimation { public enum MotionAnimation {
case delay(TimeInterval) case delay(TimeInterval)
case timingFunction(MotionAnimationTimingFunction) case timingFunction(MotionAnimationTimingFunction)
...@@ -103,750 +72,3 @@ public enum MotionAnimation { ...@@ -103,750 +72,3 @@ public enum MotionAnimation {
case shadowRadius(CGFloat) case shadowRadius(CGFloat)
case depth(shadowOffset: CGSize, shadowOpacity: Float, shadowRadius: CGFloat) case depth(shadowOffset: CGSize, shadowOpacity: Float, shadowRadius: CGFloat)
} }
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
extension CALayer {
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open func animate(_ animations: CAAnimation...) {
animate(animations)
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open func animate(_ animations: [CAAnimation]) {
for animation in animations {
if nil == animation.delegate {
animation.delegate = self
}
if let a = animation as? CABasicAnimation {
a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!)
}
if let a = animation as? CAPropertyAnimation {
add(a, forKey: a.keyPath!)
} else if let a = animation as? CAAnimationGroup {
add(a, forKey: nil)
} else if let a = animation as? CATransition {
add(a, forKey: kCATransition)
}
}
}
open func animationDidStart(_ anim: CAAnimation) {}
/**
A delegation function that is executed when the backing layer stops
running an animation.
- Parameter animation: The CAAnimation instance that stopped running.
- Parameter flag: A boolean that indicates if the animation stopped
because it was completed or interrupted. True if completed, false
if interrupted.
*/
open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
guard let a = anim as? CAPropertyAnimation else {
if let a = (anim as? CAAnimationGroup)?.animations {
for x in a {
animationDidStop(x, finished: true)
}
}
return
}
guard let b = a as? CABasicAnimation else {
return
}
guard let v = b.toValue else {
return
}
guard let k = b.keyPath else {
return
}
setValue(v, forKeyPath: k)
removeAnimation(forKey: k)
}
/**
A function that accepts a list of MotionAnimation values and executes them.
- Parameter animations: A list of MotionAnimation values.
*/
open func motion(_ animations: MotionAnimation...) {
motion(animations)
}
/**
A function that accepts an Array of MotionAnimation values and executes them.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open func motion(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
motion(delay: 0, duration: 0.35, timingFunction: .easeInEaseOut, animations: animations, completion: completion)
}
/**
A function that executes an Array of MotionAnimation values.
- Parameter delay: The animation delay TimeInterval.
- Parameter duration: The animation duration TimeInterval.
- Parameter timingFunction: The animation MotionAnimationTimingFunction.
- Parameter animations: An Array of MotionAnimations.
- Parameter completion: An optional completion block.
*/
fileprivate func motion(delay: TimeInterval, duration: TimeInterval, timingFunction: MotionAnimationTimingFunction, animations: [MotionAnimation], completion: (() -> Void)? = nil) {
var t = delay
for v in animations {
switch v {
case let .delay(time):
t = time
default:break
}
}
Motion.delay(t) { [weak self] in
guard let s = self else {
return
}
var a = [CABasicAnimation]()
var tf = timingFunction
var d = duration
var w: CGFloat = s.bounds.width
var h: CGFloat = s.bounds.height
for v in animations {
switch v {
case let .width(width):
w = width
case let .height(height):
h = height
case let .size(width, height):
w = width
h = height
default:break
}
}
var px: CGFloat = s.position.x
var py: CGFloat = s.position.y
for v in animations {
switch v {
case let .x(x):
px = x + w / 2
case let .y(y):
py = y + h / 2
case let .point(x, y):
px = x + w / 2
py = y + h / 2
default:break
}
}
for v in animations {
switch v {
case let .timingFunction(timingFunction):
tf = timingFunction
case let .duration(duration):
d = duration
case let .custom(animation):
a.append(animation)
case let .backgroundColor(color):
a.append(MotionBasicAnimation.background(color: color))
case let .barTintColor(color):
a.append(MotionBasicAnimation.barTint(color: color))
case let .borderColor(color):
a.append(MotionBasicAnimation.border(color: color))
case let .borderWidth(width):
a.append(MotionBasicAnimation.border(width: width))
case let .cornerRadius(radius):
a.append(MotionBasicAnimation.corner(radius: radius))
case let .transform(transform):
a.append(MotionBasicAnimation.transform(transform: transform))
case let .rotationAngle(angle):
let rotate = MotionBasicAnimation.rotation(angle: angle)
a.append(rotate)
case let .rotationAngleX(angle):
a.append(MotionBasicAnimation.rotationX(angle: angle))
case let .rotationAngleY(angle):
a.append(MotionBasicAnimation.rotationY(angle: angle))
case let .rotationAngleZ(angle):
a.append(MotionBasicAnimation.rotationZ(angle: angle))
case let .spin(rotations):
a.append(MotionBasicAnimation.spin(rotations: rotations))
case let .spinX(rotations):
a.append(MotionBasicAnimation.spinX(rotations: rotations))
case let .spinY(rotations):
a.append(MotionBasicAnimation.spinY(rotations: rotations))
case let .spinZ(rotations):
a.append(MotionBasicAnimation.spinZ(rotations: rotations))
case let .scale(to):
a.append(MotionBasicAnimation.scale(to: to))
case let .scaleX(to):
a.append(MotionBasicAnimation.scaleX(to: to))
case let .scaleY(to):
a.append(MotionBasicAnimation.scaleY(to: to))
case let .scaleZ(to):
a.append(MotionBasicAnimation.scaleZ(to: to))
case let .translate(x, y):
a.append(MotionBasicAnimation.translate(to: CGPoint(x: x, y: y)))
case let .translateX(to):
a.append(MotionBasicAnimation.translateX(to: to))
case let .translateY(to):
a.append(MotionBasicAnimation.translateY(to: to))
case let .translateZ(to):
a.append(MotionBasicAnimation.translateZ(to: to))
case .x(_), .y(_), .point(_, _):
let position = MotionBasicAnimation.position(to: CGPoint(x: px, y: py))
a.append(position)
case let .position(x, y):
a.append(MotionBasicAnimation.position(to: CGPoint(x: x, y: y)))
case let .fade(opacity):
let fade = MotionBasicAnimation.fade(opacity: opacity)
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)
a.append(zPosition)
case .width(_), .height(_), .size(_, _):
a.append(MotionBasicAnimation.size(CGSize(width: w, height: h)))
case let .shadowPath(path):
let shadowPath = MotionBasicAnimation.shadow(path: path)
shadowPath.fromValue = s.shadowPath
a.append(shadowPath)
case let .shadowOffset(offset):
let shadowOffset = MotionBasicAnimation.shadow(offset: offset)
shadowOffset.fromValue = s.shadowOffset
a.append(shadowOffset)
case let .shadowOpacity(opacity):
let shadowOpacity = MotionBasicAnimation.shadow(opacity: opacity)
shadowOpacity.fromValue = s.shadowOpacity
a.append(shadowOpacity)
case let .shadowRadius(radius):
let shadowRadius = MotionBasicAnimation.shadow(radius: radius)
shadowRadius.fromValue = s.shadowRadius
a.append(shadowRadius)
case let .depth(offset, opacity, radius):
if let path = s.shadowPath {
let shadowPath = MotionBasicAnimation.shadow(path: path)
shadowPath.fromValue = s.shadowPath
a.append(shadowPath)
}
let shadowOffset = MotionBasicAnimation.shadow(offset: offset)
shadowOffset.fromValue = s.shadowOffset
a.append(shadowOffset)
let shadowOpacity = MotionBasicAnimation.shadow(opacity: opacity)
shadowOpacity.fromValue = s.shadowOpacity
a.append(shadowOpacity)
let shadowRadius = MotionBasicAnimation.shadow(radius: radius)
shadowRadius.fromValue = s.shadowRadius
a.append(shadowRadius)
default:break
}
}
let g = Motion.animate(group: a, duration: d)
g.fillMode = MotionAnimationFillModeToValue(mode: .forwards)
g.isRemovedOnCompletion = false
g.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: tf)
s.animate(g)
guard let execute = completion else {
return
}
Motion.delay(d, execute: execute)
}
}
}
extension UIView {
/// Computes the rotation of the view.
open var motionRotationAngle: CGFloat {
get {
return CGFloat(atan2f(Float(transform.b), Float(transform.a))) * 180 / CGFloat(Double.pi)
}
set(value) {
transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi) * value / 180)
}
}
/// The global position of a view.
open var motionPosition: CGPoint {
return superview?.convert(layer.position, to: nil) ?? layer.position
}
/// The layer.transform of a view.
open var motionTransform: CATransform3D {
get {
return layer.transform
}
set(value) {
layer.transform = value
}
}
/// Computes the scale X axis value of the view.
open var motionScaleX: CGFloat {
return transform.a
}
/// Computes the scale Y axis value of the view.
open var motionScaleY: CGFloat {
return transform.b
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animations: A list of CAAnimations.
*/
open func animate(_ animations: CAAnimation...) {
layer.animate(animations)
}
/**
A function that accepts an Array of CAAnimation objects and executes
them on the view's backing layer.
- Parameter animations: An Array of CAAnimations.
*/
open func animate(_ animations: [CAAnimation]) {
layer.animate(animations)
}
/**
A function that accepts a list of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: A list of MotionAnimation values.
*/
open func motion(_ animations: MotionAnimation...) {
layer.motion(animations)
}
/**
A function that accepts an Array of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open func motion(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
layer.motion(animations, completion: completion)
}
}
extension CABasicAnimation {
/**
A convenience initializer that takes a given MotionAnimationKeyPath.
- Parameter keyPath: An MotionAnimationKeyPath.
*/
public convenience init(keyPath: MotionAnimationKeyPath) {
self.init(keyPath: keyPath.rawValue)
}
}
extension CAKeyframeAnimation {
/**
A convenience initializer that takes a given MotionAnimationKeyPath.
- Parameter keyPath: An MotionAnimationKeyPath.
*/
public convenience init(keyPath: MotionAnimationKeyPath) {
self.init(keyPath: keyPath.rawValue)
}
}
public struct MotionKeyframeAnimation {
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func background(color: UIColor) -> CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath: .backgroundColor)
animation.values = [color.cgColor]
return animation
}
}
public struct MotionBasicAnimation {
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func background(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .backgroundColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the barTintColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func barTint(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .barTintColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the borderColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public static func border(color: UIColor) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .borderColor)
animation.toValue = color.cgColor
return animation
}
/**
Creates a CABasicAnimation for the borderWidth key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func border(width: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .borderWidth)
animation.toValue = width
return animation
}
/**
Creates a CABasicAnimation for the cornerRadius key path.
- Parameter radius: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func corner(radius: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .cornerRadius)
animation.toValue = radius
return animation
}
/**
Creates a CABasicAnimation for the transform key path.
- Parameter transform: A CATransform3D object.
- Returns: A CABasicAnimation.
*/
public static func transform(transform: CATransform3D) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .transform)
animation.toValue = NSValue(caTransform3D: transform)
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotation(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotation)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationX(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationX)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationY(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationY)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotationZ(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationZ)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spin(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotation)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinX(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationX)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinY(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationY)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func spinZ(rotations: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotationZ)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * 2 * rotations))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scale(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scale)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.x key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleX(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleX)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.y key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleY(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleY)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.scale.z key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func scaleZ(to scale: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scaleZ)
animation.toValue = NSNumber(value: Double(scale))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation key path.
- Parameter point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public static func translate(to point: CGPoint) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translation)
animation.toValue = NSValue(cgPoint: point)
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.x key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateX(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationX)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.y key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateY(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationY)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the transform.translation.z key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func translateZ(to translation: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .translationZ)
animation.toValue = NSNumber(value: Double(translation))
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func position(x: CGFloat, y: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: CGPoint(x: x, y: y))
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter to point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public static func position(to point: CGPoint) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: point)
return animation
}
/**
Creates a CABasicAnimation for the opacity key path.
- Parameter opacity: A Double.
- Returns: A CABasicAnimation.
*/
public static func fade(opacity: Double) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .opacity)
animation.toValue = NSNumber(floatLiteral: opacity)
return animation
}
/**
Creates a CABasicaAnimation for the zPosition key path.
- Parameter index: An Int.
- Returns: A CABasicAnimation.
*/
public static func zPosition(index: Int) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .zPosition)
animation.toValue = NSNumber(integerLiteral: index)
return animation
}
/**
Creates a CABasicaAnimation for the width key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func width(_ width: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .width)
animation.toValue = NSNumber(floatLiteral: Double(width))
return animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter height: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func height(_ height: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .height)
animation.toValue = NSNumber(floatLiteral: Double(height))
return animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter size: A CGSize.
- Returns: A CABasicAnimation.
*/
public static func size(_ size: CGSize) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .size)
animation.toValue = NSValue(cgSize: size)
return animation
}
/**
Creates a CABasicAnimation for the shadowPath key path.
- Parameter path: A CGPath.
- Returns: A CABasicAnimation.
*/
public static func shadow(path: CGPath) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowPath)
animation.toValue = path
return animation
}
/**
Creates a CABasicAnimation for the shadowOffset key path.
- Parameter offset: CGSize.
- Returns: A CABasicAnimation.
*/
public static func shadow(offset: CGSize) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowOffset)
animation.toValue = NSValue(cgSize: offset)
return animation
}
/**
Creates a CABasicAnimation for the shadowOpacity key path.
- Parameter opacity: Float.
- Returns: A CABasicAnimation.
*/
public static func shadow(opacity: Float) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowOpacity)
animation.toValue = NSNumber(floatLiteral: Double(opacity))
return animation
}
/**
Creates a CABasicAnimation for the shadowRadius key path.
- Parameter radius: CGFloat.
- Returns: A CABasicAnimation.
*/
public static func shadow(radius: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowRadius)
animation.toValue = NSNumber(floatLiteral: Double(radius))
return animation
}
}
...@@ -56,4 +56,7 @@ public protocol MotionAnimator: class { ...@@ -56,4 +56,7 @@ public protocol MotionAnimator: class {
/// ///
func clean() func clean()
func apply(motionTransitions: [MotionTransitionAnimation], to view: UIView)
} }
/*
* 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.
*/
public enum MotionCascadeDirection {
case topToBottom
case bottomToTop
case leftToRight
case rightToLeft
}
...@@ -32,16 +32,16 @@ import UIKit ...@@ -32,16 +32,16 @@ import UIKit
open class MotionContext { open class MotionContext {
/// A reference to the transition container. /// A reference to the transition container.
fileprivate var transitionContainer: UIView fileprivate var container: UIView
/// An index source of identifiers to their corresponding view. /// An index source of identifiers to their corresponding view.
fileprivate var transitionSourceIdentifierToView = [String: UIView]() fileprivate var sourceIdentifierToView = [String: UIView]()
/// An index of destination identifiers to their corresponding view. /// An index of destination identifiers to their corresponding view.
fileprivate var transitionDestinationIdentifierToView = [String: UIView]() fileprivate var destinationIdentifierToView = [String: UIView]()
/// An index of views to their corresponding snapshot view. /// An index of views to their corresponding snapshot view.
fileprivate var transitionSnapshotToView = [UIView: UIView]() fileprivate var snapshotToView = [UIView: UIView]()
/// A reference to the transition from views. /// A reference to the transition from views.
fileprivate var fromViews: [UIView]! fileprivate var fromViews: [UIView]!
...@@ -51,10 +51,10 @@ open class MotionContext { ...@@ -51,10 +51,10 @@ open class MotionContext {
/** /**
An initializer that accepts a given transition container view. An initializer that accepts a given transition container view.
- Parameter transitionContainer: A UIView. - Parameter container: A UIView.
*/ */
init(transitionContainer: UIView) { init(container: UIView) {
self.transitionContainer = transitionContainer self.container = container
} }
} }
...@@ -68,13 +68,15 @@ extension MotionContext { ...@@ -68,13 +68,15 @@ extension MotionContext {
for v in views { for v in views {
v.layer.removeAllAnimations() v.layer.removeAllAnimations()
guard transitionContainer.convert(v.bounds, from: v).intersects(transitionContainer.bounds) else { guard container.convert(v.bounds, from: v).intersects(container.bounds) else {
return return
} }
if let i = v.motionIdentifier { guard let i = v.motionIdentifier else {
identifierIndex[i] = v return
} }
identifierIndex[i] = v
} }
} }
} }
...@@ -88,7 +90,7 @@ extension MotionContext { ...@@ -88,7 +90,7 @@ extension MotionContext {
fileprivate func set(fromViews: [UIView], toViews: [UIView]) { fileprivate func set(fromViews: [UIView], toViews: [UIView]) {
self.fromViews = fromViews self.fromViews = fromViews
self.toViews = toViews self.toViews = toViews
prepare(views: fromViews, identifierIndex: &transitionSourceIdentifierToView) prepare(views: fromViews, identifierIndex: &sourceIdentifierToView)
prepare(views: toViews, identifierIndex: &transitionDestinationIdentifierToView) prepare(views: toViews, identifierIndex: &destinationIdentifierToView)
} }
} }
/*
* 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.
*/
public enum MotionCoordinateSpace {
case global
case local
case parent
}
/*
* 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.
*/
public enum MotionSnapshot {
case optimized
case normal
case layerRender
case none
}
/*
* 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
public enum MotionTransitionAnimation {
case timingFunction(MotionAnimationTimingFunction)
case duration(TimeInterval)
case custom(CABasicAnimation)
case backgroundColor(UIColor)
case barTintColor(UIColor)
case borderColor(UIColor)
case borderWidth(CGFloat)
case cornerRadius(CGFloat)
case transform(CATransform3D)
case rotationAngle(CGFloat)
case rotationAngleX(CGFloat)
case rotationAngleY(CGFloat)
case rotationAngleZ(CGFloat)
case spin(CGFloat)
case spinX(CGFloat)
case spinY(CGFloat)
case spinZ(CGFloat)
case scale(CGFloat)
case scaleX(CGFloat)
case scaleY(CGFloat)
case scaleZ(CGFloat)
case translate(x: CGFloat, y: CGFloat)
case translateX(CGFloat)
case translateY(CGFloat)
case translateZ(CGFloat)
case x(CGFloat)
case y(CGFloat)
case point(x: CGFloat, y: CGFloat)
case position(x: CGFloat, y: CGFloat)
case fade(Double)
case zPosition(Int)
case width(CGFloat)
case height(CGFloat)
case size(width: CGFloat, height: CGFloat)
case shadowPath(CGPath)
case shadowOffset(CGSize)
case shadowOpacity(Float)
case shadowRadius(CGFloat)
case depth(shadowOffset: CGSize, shadowOpacity: Float, shadowRadius: CGFloat)
}
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