Commit 06f6c0cd by Daniel Dahan

fixed MotionAnimation to use MotionAnimationState phase 1

parent 787abddb
......@@ -13,6 +13,7 @@
963150DA1EE51EB4002B0D42 /* MotionAnimationFillMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */; };
966A7F091EEC422000A2DAAC /* MotionSnapshotType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966A7F081EEC422000A2DAAC /* MotionSnapshotType.swift */; };
966A7F0B1EEC424000A2DAAC /* MotionCoordinateSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966A7F0A1EEC424000A2DAAC /* MotionCoordinateSpace.swift */; };
966C17711F037CD900D3E83C /* MotionAnimationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966C17701F037CD900D3E83C /* MotionAnimationState.swift */; };
968989B91EE5B34B003B8F3D /* MotionHasInsertOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 968989B81EE5B34B003B8F3D /* MotionHasInsertOrder.swift */; };
968989DC1EE65F2B003B8F3D /* MotionPreprocessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 968989DB1EE65F2B003B8F3D /* MotionPreprocessor.swift */; };
968989DE1EE6633E003B8F3D /* MotionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 968989DD1EE6633E003B8F3D /* MotionAnimator.swift */; };
......@@ -49,6 +50,7 @@
963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MotionAnimationFillMode.swift; path = ../Extensions/MotionAnimationFillMode.swift; sourceTree = "<group>"; };
966A7F081EEC422000A2DAAC /* MotionSnapshotType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionSnapshotType.swift; sourceTree = "<group>"; };
966A7F0A1EEC424000A2DAAC /* MotionCoordinateSpace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionCoordinateSpace.swift; sourceTree = "<group>"; };
966C17701F037CD900D3E83C /* MotionAnimationState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimationState.swift; sourceTree = "<group>"; };
968989B81EE5B34B003B8F3D /* MotionHasInsertOrder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionHasInsertOrder.swift; sourceTree = "<group>"; };
968989DB1EE65F2B003B8F3D /* MotionPreprocessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionPreprocessor.swift; sourceTree = "<group>"; };
968989DD1EE6633E003B8F3D /* MotionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionAnimator.swift; sourceTree = "<group>"; };
......@@ -161,6 +163,7 @@
96C98DED1E438A5700B22906 /* Motion.h */,
96AEB6771EE4610F009A3BE0 /* Motion.swift */,
96AEB6781EE4610F009A3BE0 /* MotionController.swift */,
966C17701F037CD900D3E83C /* MotionAnimationState.swift */,
963150D41EE51C7A002B0D42 /* MotionAnimation.swift */,
96AEB6791EE4610F009A3BE0 /* MotionContext.swift */,
96AEB67A1EE4610F009A3BE0 /* MotionIndependentController.swift */,
......@@ -281,6 +284,7 @@
968989DC1EE65F2B003B8F3D /* MotionPreprocessor.swift in Sources */,
96AEB69F1EE4610F009A3BE0 /* MotionContext.swift in Sources */,
96AEB6AE1EE4610F009A3BE0 /* IgnoreSubviewModifiersPreprocessor.swift in Sources */,
966C17711F037CD900D3E83C /* MotionAnimationState.swift in Sources */,
96AEB68D1EE4610F009A3BE0 /* MotionAnimatorViewContext.swift in Sources */,
96AEB6B01EE4610F009A3BE0 /* SourcePreprocessor.swift in Sources */,
963150D21EE50DA6002B0D42 /* Motion+Obj-C.swift in Sources */,
......
......@@ -44,13 +44,13 @@ internal extension CALayer {
}
}
extension CALayer {
public extension CALayer {
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
public func animate(_ animations: CAAnimation...) {
func animate(_ animations: CAAnimation...) {
animate(animations)
}
......@@ -59,7 +59,7 @@ extension CALayer {
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
public func animate(_ animations: [CAAnimation]) {
func animate(_ animations: [CAAnimation]) {
for animation in animations {
if nil == animation.delegate {
animation.delegate = self
......@@ -83,7 +83,7 @@ extension CALayer {
Executed when an animation has started.
- Parameter _ anim: A CAAnimation.
*/
public func animationDidStart(_ anim: CAAnimation) {}
func animationDidStart(_ anim: CAAnimation) {}
/**
A delegation function that is executed when the backing layer stops
......@@ -93,7 +93,7 @@ extension CALayer {
because it was completed or interrupted. True if completed, false
if interrupted.
*/
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
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 {
......@@ -123,7 +123,7 @@ extension CALayer {
A function that accepts a list of MotionAnimation values and executes them.
- Parameter animations: A list of MotionAnimation values.
*/
public func animate(_ animations: MotionAnimation...) {
func animate(_ animations: MotionAnimation...) {
animate(animations)
}
......@@ -132,10 +132,12 @@ extension CALayer {
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
public func animate(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
func animate(_ animations: [MotionAnimation], completion: (() -> Void)? = nil) {
animate(delay: 0, duration: 0.35, timingFunction: .easeInOut, animations: animations, completion: completion)
}
}
fileprivate extension CALayer {
/**
A function that executes an Array of MotionAnimation values.
- Parameter delay: The animation delay TimeInterval.
......@@ -144,213 +146,182 @@ extension CALayer {
- Parameter animations: An Array of MotionAnimations.
- Parameter completion: An optional completion block.
*/
fileprivate func animate(delay: TimeInterval, duration: TimeInterval, timingFunction: CAMediaTimingFunctionType, animations: [MotionAnimation], completion: (() -> Void)? = nil) {
var t = delay
func animate(delay: TimeInterval, duration: TimeInterval, timingFunction: CAMediaTimingFunctionType, animations: [MotionAnimation], completion: (() -> Void)? = nil) {
for v in animations {
switch v {
case let .delay(time):
t = time
default:break
}
}
let targetState = MotionAnimationState(animations: animations)
Motion.delay(t) { [weak self] in
Motion.delay(targetState.delay) { [weak self] in
guard let s = self else {
return
}
var a = [CABasicAnimation]()
var tf = timingFunction
var d = duration
let tf: CAMediaTimingFunction = targetState.timingFunction ?? CAMediaTimingFunction.from(mediaTimingFunctionType: timingFunction)
let d: TimeInterval = targetState.duration ?? duration
//
// var w: CGFloat = s.bounds.width
// var h: CGFloat = s.bounds.height
//
//
// 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
// }
// }
//
if let v = targetState.backgroundColor {
let anim = MotionBasicAnimation.background(color: UIColor(cgColor: v))
anim.fromValue = s.backgroundColor
a.append(anim)
}
var w: CGFloat = s.bounds.width
var h: CGFloat = s.bounds.height
if let v = targetState.borderColor {
let anim = MotionBasicAnimation.border(color: UIColor(cgColor: v))
anim.fromValue = s.borderColor
a.append(anim)
}
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
}
if let v = targetState.borderWidth {
let anim = MotionBasicAnimation.border(width: v)
anim.fromValue = NSNumber(floatLiteral: Double(s.borderWidth))
a.append(anim)
}
var px: CGFloat = s.position.x
var py: CGFloat = s.position.y
if let v = targetState.cornerRadius {
let anim = MotionBasicAnimation.corner(radius: v)
anim.fromValue = NSNumber(floatLiteral: Double(s.cornerRadius))
a.append(anim)
}
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
}
if let v = targetState.transform {
let anim = MotionBasicAnimation.transform(transform: v)
anim.fromValue = NSValue(caTransform3D: s.transform)
a.append(anim)
}
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 .rotate(angle):
let rotate = MotionBasicAnimation.rotate(angle: angle)
a.append(rotate)
case let .rotateX(angle):
a.append(MotionBasicAnimation.rotateX(angle: angle))
case let .rotateY(angle):
a.append(MotionBasicAnimation.rotateY(angle: angle))
case let .rotateZ(angle):
a.append(MotionBasicAnimation.rotateZ(angle: angle))
case let .spin(rotates):
a.append(MotionBasicAnimation.spin(rotates: rotates))
case let .spinX(rotates):
a.append(MotionBasicAnimation.spinX(rotates: rotates))
case let .spinY(rotates):
a.append(MotionBasicAnimation.spinY(rotates: rotates))
case let .spinZ(rotates):
a.append(MotionBasicAnimation.spinZ(rotates: rotates))
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(to: opacity)
fade.fromValue = s.value(forKey: MotionAnimationKeyPath.opacity.rawValue) ?? NSNumber(floatLiteral: 1)
a.append(fade)
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(_, _):
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 .shadowColor(color):
a.append(MotionBasicAnimation.shadow(color: color))
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
}
if let v = targetState.spin {
var anim = MotionBasicAnimation.spinX(rotates: v.0)
anim.fromValue = 0
a.append(anim)
anim = MotionBasicAnimation.spinY(rotates: v.1)
anim.fromValue = 0
a.append(anim)
anim = MotionBasicAnimation.spinZ(rotates: v.2)
anim.fromValue = 0
a.append(anim)
}
//
// 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(to: opacity)
// fade.fromValue = s.value(forKey: MotionAnimationKeyPath.opacity.rawValue) ?? NSNumber(floatLiteral: 1)
// a.append(fade)
//
// 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(_, _):
// 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 .shadowColor(color):
// a.append(MotionBasicAnimation.shadow(color: color))
//
// 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 = CAMediaTimingFunction.from(mediaTimingFunctionType: tf)
g.timingFunction = tf
s.animate(g)
......
......@@ -84,16 +84,6 @@ public extension UIView {
}
}
/// The animations to run.
var motionAnimations: [MotionAnimation]? {
get {
return associatedInstance.animations
}
set(value) {
associatedInstance.animations = value
}
}
/// The animations to run while in transition.
var motionTransitions: [MotionTransition]? {
get {
......
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
* The MIT License (MIT)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* * 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.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* * 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.
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import UIKit
public enum MotionAnimation {
case delay(TimeInterval)
case timingFunction(CAMediaTimingFunctionType)
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 rotate(CGFloat)
case rotateX(CGFloat)
case rotateY(CGFloat)
case rotateZ(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(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)
case depth(shadowOffset: CGSize, shadowOpacity: Float, shadowRadius: CGFloat)
public final class MotionAnimation {
/// A reference to the callback that applies the MotionAnimationState.
internal let apply: (inout MotionAnimationState) -> Void
/**
An initializer that accepts a given callback.
- Parameter applyFunction: A given callback.
*/
public init(applyFunction: @escaping (inout MotionAnimationState) -> Void) {
apply = applyFunction
}
}
extension MotionAnimation {
/**
Animates the view's current background color to the
given color.
- Parameter color: A UIColor.
- Returns: A MotionAnimation.
*/
public static func background(color: UIColor) -> MotionAnimation {
return MotionAnimation {
$0.backgroundColor = color.cgColor
}
}
/**
Animates the view's current border color to the
given color.
- Parameter color: A UIColor.
- Returns: A MotionAnimation.
*/
public static func border(color: UIColor) -> MotionAnimation {
return MotionAnimation {
$0.borderColor = color.cgColor
}
}
/**
Animates the view's current border width to the
given width.
- Parameter width: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func border(width: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.borderWidth = width
}
}
/**
Animates the view's current corner radius to the
given radius.
- Parameter radius: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func corner(radius: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.cornerRadius = radius
}
}
/**
Animates the view's current transform (perspective, scale, rotate)
to the given one.
- Parameter _ transform: A CATransform3D.
- Returns: A MotionAnimation.
*/
public static func transform(_ transform: CATransform3D) -> MotionAnimation {
return MotionAnimation {
$0.transform = transform
}
}
/**
Animates the view's current perspective to the gievn one through
a CATransform3D object.
- Parameter _ perspective: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func perspective(_ perspective: CGFloat) -> MotionAnimation {
return MotionAnimation {
var t = $0.transform ?? CATransform3DIdentity
t.m34 = 1 / -perspective
$0.transform = t
}
}
/**
Animates the view's current rotate to the given x, y,
and z values.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Parameter z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func rotate(x: CGFloat = 0, y: CGFloat = 0, z: CGFloat = 0) -> MotionAnimation {
return MotionAnimation {
var t = $0.transform ?? CATransform3DIdentity
t = CATransform3DRotate(t, CGFloat(Double.pi) * x / 180, 1, 0, 0)
t = CATransform3DRotate(t, CGFloat(Double.pi) * y / 180, 0, 1, 0)
$0.transform = CATransform3DRotate(t, CGFloat(Double.pi) * z / 180, 0, 0, 1)
}
}
/**
Animates the view's current rotate to the given point.
- Parameter _ point: A CGPoint.
- Parameter z: A CGFloat, default is 0.
- Returns: A MotionAnimation.
*/
public static func rotate(_ point: CGPoint, z: CGFloat = 0) -> MotionAnimation {
return .rotate(x: point.x, y: point.y, z: z)
}
/**
Rotate 2d.
- Parameter _ z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func rotate(_ z: CGFloat) -> MotionAnimation {
return .rotate(z: z)
}
/**
Animates the view's current spin to the given x, y,
and z values.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Parameter z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func spin(x: CGFloat = 0, y: CGFloat = 0, z: CGFloat = 0) -> MotionAnimation {
return MotionAnimation {
$0.spin = (x, y, z)
}
}
/**
Animates the view's current spin to the given point.
- Parameter _ point: A CGPoint.
- Parameter z: A CGFloat, default is 0.
- Returns: A MotionAnimation.
*/
public static func spin(_ point: CGPoint, z: CGFloat = 0) -> MotionAnimation {
return .spin(x: point.x, y: point.y, z: z)
}
/**
Spin 2d.
- Parameter _ z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func spin(_ z: CGFloat) -> MotionAnimation {
return .spin(z: z)
}
/**
Animates the view's current scale to the given x, y, z scale values.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Parameter z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func scale(x: CGFloat = 1, y: CGFloat = 1, z: CGFloat = 1) -> MotionAnimation {
return MotionAnimation {
$0.transform = CATransform3DScale($0.transform ?? CATransform3DIdentity, x, y, z)
}
}
/**
Animates the view's current x & y scale to the given scale value.
- Parameter to scale: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func scale(to scale: CGFloat) -> MotionAnimation {
return .scale(x: scale, y: scale)
}
/**
Animates the view's current translation to the given
x, y, and z values.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Parameter z: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func translate(x: CGFloat = 0, y: CGFloat = 0, z: CGFloat = 0) -> MotionAnimation {
return MotionAnimation {
$0.transform = CATransform3DTranslate($0.transform ?? CATransform3DIdentity, x, y, z)
}
}
/**
Animates the view's current translation to the given
point value (x & y), and a z value.
- Parameter to point: A CGPoint.
- Parameter z: A CGFloat, default is 0.
- Returns: A MotionAnimation.
*/
public static func translate(to point: CGPoint, z: CGFloat = 0) -> MotionAnimation {
return .translate(x: point.x, y: point.y, z: z)
}
/**
Animates the view's current position to the given point.
- Parameter to point: A CGPoint.
- Returns: A MotionAnimation.
*/
public static func position(to point: CGPoint) -> MotionAnimation {
return MotionAnimation {
$0.position = point
}
}
/// Fades the view out during a transition.
public static var fade = MotionAnimation {
$0.opacity = 0
}
/**
Animates the view's current opacity to the given one.
- Parameter to opacity: A Float value.
- Returns: A MotionAnimation.
*/
public static func fade(to opacity: Float) -> MotionAnimation {
return MotionAnimation {
$0.opacity = opacity
}
}
/**
Animates the view's current zPosition to the given position.
- Parameter _ position: An Int.
- Returns: A MotionAnimation.
*/
public static func zPosition(_ position: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.zPosition = position
}
}
/**
Animates the view's current size to the given one.
- Parameter _ size: A CGSize.
- Returns: A MotionAnimation.
*/
public static func size(_ size: CGSize) -> MotionAnimation {
return MotionAnimation {
$0.size = size
}
}
/**
Animates the view's current shadow path to the given one.
- Parameter path: A CGPath.
- Returns: A MotionAnimation.
*/
public static func shadow(path: CGPath) -> MotionAnimation {
return MotionAnimation {
$0.shadowPath = path
}
}
/**
Animates the view's current shadow color to the given one.
- Parameter color: A UIColor.
- Returns: A MotionAnimation.
*/
public static func shadow(color: UIColor) -> MotionAnimation {
return MotionAnimation {
$0.shadowColor = color.cgColor
}
}
/**
Animates the view's current shadow offset to the given one.
- Parameter offset: A CGSize.
- Returns: A MotionAnimation.
*/
public static func shadow(offset: CGSize) -> MotionAnimation {
return MotionAnimation {
$0.shadowOffset = offset
}
}
/**
Animates the view's current shadow opacity to the given one.
- Parameter opacity: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func shadow(opacity: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.shadowOpacity = Float(opacity)
}
}
/**
Animates the view's current shadow radius to the given one.
- Parameter radius: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func shadow(radius: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.shadowRadius = radius
}
}
/**
Animates the view's contents rect to the given one.
- Parameter rect: A CGRect.
- Returns: A MotionAnimation.
*/
public static func contents(rect: CGRect) -> MotionAnimation {
return MotionAnimation {
$0.contentsRect = rect
}
}
/**
Animates the view's contents scale to the given one.
- Parameter scale: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func contents(scale: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.contentsScale = scale
}
}
/**
The duration of the view's animation.
- Parameter _ duration: A TimeInterval.
- Returns: A MotionAnimation.
*/
public static func duration(_ duration: TimeInterval) -> MotionAnimation {
return MotionAnimation {
$0.duration = duration
}
}
/**
Sets the view's animation duration to the longest
running animation within a transition.
*/
public static var preferredDurationMatchesLongest = MotionAnimation.duration(.infinity)
/**
Delays the animation of a given view.
- Parameter _ time: TimeInterval.
- Returns: A MotionAnimation.
*/
public static func delay(_ time: TimeInterval) -> MotionAnimation {
return MotionAnimation {
$0.delay = time
}
}
/**
Sets the view's timing function for the animation.
- Parameter _ timingFunction: A CAMediaTimingFunction.
- Returns: A MotionAnimation.
*/
public static func timingFunction(_ timingFunction: CAMediaTimingFunction) -> MotionAnimation {
return MotionAnimation {
$0.timingFunction = timingFunction
}
}
/**
Available in iOS 9+, animates a view using the spring API,
given a stiffness and damping.
- Parameter stiffness: A CGFlloat.
- Parameter damping: A CGFloat.
- Returns: A MotionAnimation.
*/
@available(iOS 9, *)
public static func spring(stiffness: CGFloat, damping: CGFloat) -> MotionAnimation {
return MotionAnimation {
$0.spring = (stiffness, damping)
}
}
/**
Animates the natural curve of a view. A value of 1 represents
a curve in a downward direction, and a value of -1
represents a curve in an upward direction.
- Parameter intensity: A CGFloat.
- Returns: A MotionAnimation.
*/
public static func arc(intensity: CGFloat = 1) -> MotionAnimation {
return MotionAnimation {
$0.arc = intensity
}
}
/**
Animates subviews with an increasing delay between each animation.
- Parameter delta: A TimeInterval.
- Parameter direction: A CascadeDirection.
- Parameter animationDelayUntilMatchedViews: A boolean indicating whether
or not to delay the subview animation until all have started.
- Returns: A MotionAnimation.
*/
public static func cascade(delta: TimeInterval = 0.02, direction: CascadeDirection = .topToBottom, animationDelayUntilMatchedViews: Bool = false) -> MotionAnimation {
return MotionAnimation {
$0.cascade = (delta, direction, animationDelayUntilMatchedViews)
}
}
}
public enum MotionAnimationKeyPath: String {
......@@ -185,50 +550,6 @@ public struct MotionBasicAnimation {
/**
Creates a CABasicAnimation for the transform.rotate key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotate(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotate)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotate.x key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotateX(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotateX)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotate.y key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotateY(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotateY)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotate.z key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public static func rotateZ(angle: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .rotateZ)
animation.toValue = NSNumber(value: Double(CGFloat(Double.pi) * angle / 180))
return animation
}
/**
Creates a CABasicAnimation for the transform.rotate key path.
- Parameter rotates: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
......
/*
* The MIT License (MIT)
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import UIKit
public struct MotionAnimationState {
/// A reference to the position.
public var position: CGPoint?
/// A reference to the size.
public var size: CGSize?
/// A reference to the transform.
public var transform: CATransform3D?
/// A reference to the spin tuple.
public var spin: (CGFloat, CGFloat, CGFloat)?
/// A reference to the opacity.
public var opacity: Float?
/// A reference to the cornerRadius.
public var cornerRadius: CGFloat?
/// A reference to the backgroundColor.
public var backgroundColor: CGColor?
/// A reference to the zPosition.
public var zPosition: CGFloat?
/// A reference to the contentsRect.
public var contentsRect: CGRect?
/// A reference to the contentsScale.
public var contentsScale: CGFloat?
/// A reference to the borderWidth.
public var borderWidth: CGFloat?
/// A reference to the borderColor.
public var borderColor: CGColor?
/// A reference to the shadowColor.
public var shadowColor: CGColor?
/// A reference to the shadowOpacity.
public var shadowOpacity: Float?
/// A reference to the shadowOffset.
public var shadowOffset: CGSize?
/// A reference to the shadowRadius.
public var shadowRadius: CGFloat?
/// A reference to the shadowPath.
public var shadowPath: CGPath?
/// A reference to the spring animation settings.
public var spring: (CGFloat, CGFloat)?
/// A time delay on starting the animation.
public var delay: TimeInterval = 0
/// The duration of the animation.
public var duration: TimeInterval?
/// The timing function value of the animation.
public var timingFunction: CAMediaTimingFunction?
/// The arc curve value.
public var arc: CGFloat?
/// The cascading animation settings.
public var cascade: (TimeInterval, CascadeDirection, Bool)?
/// Custom target states.
public var custom: [String: Any]?
/**
An initializer that accepts an Array of MotionAnimations.
- Parameter animations: An Array of MotionAnimations.
*/
init(animations: [MotionAnimation]) {
append(contentsOf: animations)
}
}
extension MotionAnimationState {
/**
Adds a MotionAnimation to the current state.
- Parameter _ animation: A MotionAnimation.
*/
public mutating func append(_ animation: MotionAnimation) {
animation.apply(&self)
}
/**
Adds an Array of MotionAnimations to the current state.
- Parameter contentsOf animations: An Array of MotionAnimations.
*/
public mutating func append(contentsOf animations: [MotionAnimation]) {
for v in animations {
v.apply(&self)
}
}
/**
A subscript that returns a custom value for a specified key.
- Parameter key: A String.
- Returns: An optional Any value.
*/
public subscript(key: String) -> Any? {
get {
return custom?[key]
}
set(value) {
if nil == custom {
custom = [:]
}
custom![key] = value
}
}
}
extension MotionAnimationState: ExpressibleByArrayLiteral {
/**
An initializer implementing the ExpressibleByArrayLiteral protocol.
- Parameter arrayLiteral elements: A list of MotionAnimations.
*/
public init(arrayLiteral elements: MotionAnimation...) {
append(contentsOf: elements)
}
}
......@@ -235,8 +235,8 @@ extension MotionTransition {
}
/// Forces the view to not fade during a transition.
public static var forceNonFade = MotionTransition { targetState in
targetState.nonFade = true
public static var forceNonFade = MotionTransition {
$0.nonFade = true
}
/// Fades the view out during a transition.
......@@ -447,7 +447,6 @@ extension MotionTransition {
}
}
// advance transitions
extension MotionTransition {
/**
Apply transitions directly to the view at the start of the transition.
......
......@@ -257,27 +257,29 @@ class TransitionPreprocessor: MotionPreprocessor {
.shadow(color: .black),
.shadow(radius: 5),
.shadow(offset: .zero),
.masksToBounds(false)]
.masksToBounds(false)]
switch defaultAnimation {
case .push(let direction):
context[tv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: false) / 3),
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
case .pull(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: true) / 3),
.overlay(color: .black, opacity: 0.1)])
.overlay(color: .black, opacity: 0.1)])
case .slide(let direction):
context[fv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: false))])
......@@ -290,39 +292,42 @@ class TransitionPreprocessor: MotionPreprocessor {
case .cover(let direction):
context[tv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
.timingFunction(.deceleration)])
case .uncover(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.overlay(color: .black, opacity: 0.1)])
case .pageIn(let direction):
context[tv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: true)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState),
.timingFunction(.deceleration)])
context[fv]!.append(contentsOf: [.scale(to: 0.7),
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
.overlay(color: .black, opacity: 0.1),
.timingFunction(.deceleration)])
case .pageOut(let direction):
m.insertToViewFirst = true
context[fv]!.append(contentsOf: [.translate(to: shift(direction: direction, isAppearing: false)),
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
.shadow(opacity: 0),
.beginWith(transitions: shadowState)])
context[tv]!.append(contentsOf: [.scale(to: 0.7),
.overlay(color: .black, opacity: 0.1)])
.overlay(color: .black, opacity: 0.1)])
case .fade:
// TODO: clean up this. overFullScreen logic shouldn't be here
if !(fromOverFullScreen && !isPresenting) {
......
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