Commit 1dfc3fb8 by Daniel Dahan

updated Motion identifier values and internal handling of associated objects

parent 398021c6
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
96AEB6951EE4610F009A3BE0 /* Motion+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */; }; 96AEB6951EE4610F009A3BE0 /* Motion+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */; };
96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */; }; 96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */; };
96AEB6971EE4610F009A3BE0 /* Motion+CG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */; }; 96AEB6971EE4610F009A3BE0 /* Motion+CG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */; };
96AEB6981EE4610F009A3BE0 /* Motion+DispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6721EE4610F009A3BE0 /* Motion+DispatchQueue.swift */; };
96AEB6991EE4610F009A3BE0 /* Motion+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */; }; 96AEB6991EE4610F009A3BE0 /* Motion+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */; };
96AEB69A1EE4610F009A3BE0 /* Motion+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */; }; 96AEB69A1EE4610F009A3BE0 /* Motion+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */; };
96AEB69B1EE4610F009A3BE0 /* Motion+UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */; }; 96AEB69B1EE4610F009A3BE0 /* Motion+UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */; };
...@@ -69,7 +68,6 @@ ...@@ -69,7 +68,6 @@
96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CALayer.swift"; sourceTree = "<group>"; }; 96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CALayer.swift"; sourceTree = "<group>"; };
96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CAMediaTimingFunction.swift"; sourceTree = "<group>"; }; 96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CAMediaTimingFunction.swift"; sourceTree = "<group>"; };
96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CG.swift"; sourceTree = "<group>"; }; 96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+CG.swift"; sourceTree = "<group>"; };
96AEB6721EE4610F009A3BE0 /* Motion+DispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+DispatchQueue.swift"; sourceTree = "<group>"; };
96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIKit.swift"; sourceTree = "<group>"; }; 96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIKit.swift"; sourceTree = "<group>"; };
96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIView.swift"; sourceTree = "<group>"; }; 96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIView.swift"; sourceTree = "<group>"; };
96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIViewController.swift"; sourceTree = "<group>"; }; 96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Motion+UIViewController.swift"; sourceTree = "<group>"; };
...@@ -139,11 +137,10 @@ ...@@ -139,11 +137,10 @@
96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */, 96AEB66F1EE4610F009A3BE0 /* Motion+CALayer.swift */,
96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */, 96AEB6701EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift */,
96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */, 96AEB6711EE4610F009A3BE0 /* Motion+CG.swift */,
96AEB6721EE4610F009A3BE0 /* Motion+DispatchQueue.swift */, 963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */,
96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */, 96AEB6731EE4610F009A3BE0 /* Motion+UIKit.swift */,
96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */, 96AEB6741EE4610F009A3BE0 /* Motion+UIView.swift */,
96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */, 96AEB6751EE4610F009A3BE0 /* Motion+UIViewController.swift */,
963150D11EE50DA6002B0D42 /* Motion+Obj-C.swift */,
963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */, 963150D91EE51EB4002B0D42 /* MotionAnimationFillMode.swift */,
); );
path = Extensions; path = Extensions;
...@@ -311,7 +308,6 @@ ...@@ -311,7 +308,6 @@
96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */, 96AEB6961EE4610F009A3BE0 /* Motion+CAMediaTimingFunction.swift in Sources */,
96AEB6941EE4610F009A3BE0 /* Motion+Array.swift in Sources */, 96AEB6941EE4610F009A3BE0 /* Motion+Array.swift in Sources */,
96AEB6951EE4610F009A3BE0 /* Motion+CALayer.swift in Sources */, 96AEB6951EE4610F009A3BE0 /* Motion+CALayer.swift in Sources */,
96AEB6981EE4610F009A3BE0 /* Motion+DispatchQueue.swift in Sources */,
96AEB6A61EE4610F009A3BE0 /* MotionTypes.swift in Sources */, 96AEB6A61EE4610F009A3BE0 /* MotionTypes.swift in Sources */,
96AEB68E1EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift in Sources */, 96AEB68E1EE4610F009A3BE0 /* MotionCoreAnimationViewContext.swift in Sources */,
96AEB6921EE4610F009A3BE0 /* MotionDebugView.swift in Sources */, 96AEB6921EE4610F009A3BE0 /* MotionDebugView.swift in Sources */,
......
...@@ -56,7 +56,7 @@ class MotionDebugView: UIView { ...@@ -56,7 +56,7 @@ class MotionDebugView: UIView {
} }
var showOnTop: Bool = false var showOnTop: Bool = false
var rotation: CGFloat = π / 6 var rotation: CGFloat = .pi / 6
var scale: CGFloat = 0.6 var scale: CGFloat = 0.6
var translation: CGPoint = .zero var translation: CGPoint = .zero
var progress: Float { var progress: Float {
...@@ -145,10 +145,10 @@ class MotionDebugView: UIView { ...@@ -145,10 +145,10 @@ class MotionDebugView: UIView {
startRotation = rotation startRotation = rotation
} }
rotation = startRotation + panGR.translation(in: nil).x / 150 rotation = startRotation + panGR.translation(in: nil).x / 150
if rotation > π { if rotation > .pi {
rotation -= 2 * π rotation -= 2 * .pi
} else if rotation < -π { } else if rotation < -.pi {
rotation += 2 * π rotation += 2 * .pi
} }
delegate?.onPerspectiveChanged(translation:translation, rotation: rotation, scale:scale) delegate?.onPerspectiveChanged(translation:translation, rotation: rotation, scale:scale)
} }
......
/* /*
* The MIT License (MIT) * Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved. * All rights reserved.
* *
* Original Inspiration & Author * Redistribution and use in source and binary forms, with or without
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com> * 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.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * * Redistributions in binary form must reproduce the above copyright notice,
* of this software and associated documentation files (the "Software"), to deal * this list of conditions and the following disclaimer in the documentation
* in the Software without restriction, including without limitation the rights * and/or other materials provided with the distribution.
* 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 * * Neither the name of CosmicMind nor the names of its
* all copies or substantial portions of the Software. * contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* THE SOFTWARE. * 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 MetalKit import MetalKit
let π = CGFloat.pi
internal struct KeySet<Key: Hashable, Value: Hashable> { internal struct KeySet<Key: Hashable, Value: Hashable> {
var dict: [Key:Set<Value>] = [:] /// A reference to the dictionary storing the key / Set pairs.
internal subscript(key: Key) -> Set<Value> { fileprivate var dictionary = [Key: Set<Value>]()
mutating get {
if dict[key] == nil { /**
dict[key] = Set<Value>() Subscript for matching keys and returning the corresponding set.
} - Parameter key: A Key type.
return dict[key]! - Returns: A Set<Value> type.
*/
subscript(key: Key) -> Set<Value> {
mutating get {
if nil == dictionary[key] {
dictionary[key] = Set<Value>()
}
return dictionary[key]!
}
set(value) {
dictionary[key] = value
}
} }
set {
dict[key] = newValue
}
}
} }
internal extension CGSize { internal extension CGSize {
internal var center: CGPoint { internal var center: CGPoint {
return CGPoint(x: width / 2, y: height / 2) return CGPoint(x: width / 2, y: height / 2)
} }
internal var point: CGPoint {
return CGPoint(x: width, y: height) internal var point: CGPoint {
} return CGPoint(x: width, y: height)
internal func transform(_ t: CGAffineTransform) -> CGSize { }
return self.applying(t)
} internal func transform(_ t: CGAffineTransform) -> CGSize {
internal func transform(_ t: CATransform3D) -> CGSize { return applying(t)
return self.applying(CATransform3DGetAffineTransform(t)) }
}
internal func transform(_ t: CATransform3D) -> CGSize {
return applying(CATransform3DGetAffineTransform(t))
}
} }
internal extension CGRect { internal extension CGRect {
internal var center: CGPoint { var center: CGPoint {
return CGPoint(x: origin.x + size.width/2, y: origin.y + size.height/2) return CGPoint(x: origin.x + size.width / 2, y: origin.y + size.height / 2)
} }
internal var bounds: CGRect {
return CGRect(origin: CGPoint.zero, size: size) var bounds: CGRect {
} return CGRect(origin: CGPoint.zero, size: size)
init(center: CGPoint, size: CGSize) { }
self.init(x: center.x - size.width/2, y: center.y - size.height/2, width: size.width, height: size.height)
} init(center: CGPoint, size: CGSize) {
self.init(x: center.x - size.width / 2, y: center.y - size.height / 2, width: size.width, height: size.height)
}
} }
extension CGFloat { internal extension CGFloat {
internal func clamp(_ a: CGFloat, _ b: CGFloat) -> CGFloat { func clamp(_ a: CGFloat, _ b: CGFloat) -> CGFloat {
return self < a ? a : (self > b ? b : self) return self < a ? a : self > b ? b : self
} }
} }
extension CGPoint {
internal func translate(_ dx: CGFloat, dy: CGFloat) -> CGPoint {
return CGPoint(x: self.x+dx, y: self.y+dy)
}
internal func transform(_ t: CGAffineTransform) -> CGPoint { internal extension CGPoint {
return self.applying(t) func translate(_ dx: CGFloat, dy: CGFloat) -> CGPoint {
} return CGPoint(x: x + dx, y: y + dy)
}
internal func transform(_ t: CATransform3D) -> CGPoint {
return self.applying(CATransform3DGetAffineTransform(t)) func transform(_ t: CGAffineTransform) -> CGPoint {
} return applying(t)
}
internal func distance(_ b: CGPoint) -> CGFloat {
return sqrt(pow(self.x - b.x, 2) + pow(self.y - b.y, 2)) func transform(_ t: CATransform3D) -> CGPoint {
} return applying(CATransform3DGetAffineTransform(t))
}
func distance(_ b: CGPoint) -> CGFloat {
return sqrt(pow(x - b.x, 2) + pow(y - b.y, 2))
}
} }
internal func + (left: CGPoint, right: CGPoint) -> CGPoint { internal func +(left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x + right.x, y: left.y + right.y) return CGPoint(x: left.x + right.x, y: left.y + right.y)
} }
internal func - (left: CGPoint, right: CGPoint) -> CGPoint { internal func -(left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x - right.x, y: left.y - right.y) return CGPoint(x: left.x - right.x, y: left.y - right.y)
} }
internal func / (left: CGPoint, right: CGFloat) -> CGPoint { internal func /(left: CGPoint, right: CGFloat) -> CGPoint {
return CGPoint(x: left.x/right, y: left.y/right) return CGPoint(x: left.x / right, y: left.y / right)
} }
internal func / (left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x/right.x, y: left.y/right.y) internal func /(left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x / right.x, y: left.y / right.y)
} }
internal func * (left: CGPoint, right: CGFloat) -> CGPoint {
return CGPoint(x: left.x*right, y: left.y*right) internal func *(left: CGPoint, right: CGFloat) -> CGPoint {
return CGPoint(x: left.x * right, y: left.y * right)
} }
internal func * (left: CGPoint, right: CGSize) -> CGPoint {
return CGPoint(x: left.x*right.width, y: left.y*right.width) internal func *(left: CGPoint, right: CGSize) -> CGPoint {
return CGPoint(x: left.x * right.width, y: left.y * right.width)
} }
internal func * (left: CGFloat, right: CGPoint) -> CGPoint {
return right * left internal func *(left: CGFloat, right: CGPoint) -> CGPoint {
return right * left
} }
internal func * (left: CGPoint, right: CGPoint) -> CGPoint { internal func *(left: CGPoint, right: CGPoint) -> CGPoint {
return CGPoint(x: left.x*right.x, y: left.y*right.y) return CGPoint(x: left.x * right.x, y: left.y * right.y)
} }
internal prefix func - (point: CGPoint) -> CGPoint { internal prefix func -(point: CGPoint) -> CGPoint {
return CGPoint.zero - point return CGPoint.zero - point
} }
internal func abs(_ p: CGPoint) -> CGPoint { internal func abs(_ p: CGPoint) -> CGPoint {
return CGPoint(x: abs(p.x), y: abs(p.y)) return CGPoint(x: abs(p.x), y: abs(p.y))
} }
internal func * (left: CGSize, right: CGFloat) -> CGSize { internal func *(left: CGSize, right: CGFloat) -> CGSize {
return CGSize(width: left.width*right, height: left.height*right) return CGSize(width: left.width * right, height: left.height * right)
} }
internal func * (left: CGSize, right: CGSize) -> CGSize {
return CGSize(width: left.width*right.width, height: left.height*right.width) internal func *(left: CGSize, right: CGSize) -> CGSize {
return CGSize(width: left.width * right.width, height: left.height * right.width)
} }
internal func / (left: CGSize, right: CGSize) -> CGSize {
return CGSize(width: left.width/right.width, height: left.height/right.height) internal func /(left: CGSize, right: CGSize) -> CGSize {
return CGSize(width: left.width / right.width, height: left.height / right.height)
} }
internal func == (lhs: CATransform3D, rhs: CATransform3D) -> Bool { internal func == (lhs: CATransform3D, rhs: CATransform3D) -> Bool {
var lhs = lhs var lhs = lhs
var rhs = rhs var rhs = rhs
return memcmp(&lhs, &rhs, MemoryLayout<CATransform3D>.size) == 0 return memcmp(&lhs, &rhs, MemoryLayout<CATransform3D>.size) == 0
} }
internal func != (lhs: CATransform3D, rhs: CATransform3D) -> Bool { internal func != (lhs: CATransform3D, rhs: CATransform3D) -> Bool {
return !(lhs == rhs) return !(lhs == rhs)
} }
/*
* The MIT License (MIT)
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import Foundation
func delay(_ time: Double, execute: @escaping () -> Void) {
if time > 0 {
DispatchQueue.main.asyncAfter(deadline: .now() + time, execute: execute)
} else {
DispatchQueue.main.async(execute: execute)
}
}
...@@ -51,49 +51,101 @@ internal extension UIView { ...@@ -51,49 +51,101 @@ internal extension UIView {
} }
} }
public extension UIView { fileprivate var MotionInstanceKey: UInt8 = 0
private struct AssociatedKeys {
static var motionID = "motionID"
static var motionModifiers = "motionModifers"
static var motionStoredAlpha = "motionStoredAlpha"
static var motionEnabled = "motionEnabled"
}
/**
**motionID** is the identifier for the view. When doing a transition between two view controllers,
Motion will search through all the subviews for both view controllers and matches views with the same **motionID**.
Whenever a pair is discovered, fileprivate struct MotionInstance {
Motion will automatically transit the views from source state to the destination state. /// A boolean indicating whether Motion is enabled.
*/ fileprivate var isEnabled: Bool
@IBInspectable public var motionID: String? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionID) as? String } /// An optional reference to the motion identifier.
set { objc_setAssociatedObject(self, &AssociatedKeys.motionID, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } fileprivate var identifier: String?
}
/// An optional reference to the motion animations.
fileprivate var animations: [MotionAnimation]?
/// An optional reference to the motion transition animations.
fileprivate var transitions: [MotionTransition]?
/// An alpha value.
fileprivate var alpha: CGFloat?
}
/** extension UIView {
**isMotionEnabled** allows to specify whether a view and its subviews should be consider for animations. /// MotionInstance reference.
If true, Motion will search through all the subviews for motionIds and modifiers. Defaults to true fileprivate var motionInstance: MotionInstance {
*/ get {
@IBInspectable public var isMotionEnabled: Bool { return AssociatedObject.get(base: self, key: &MotionInstanceKey) {
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionEnabled) as? Bool ?? true } return MotionInstance(isEnabled: true, identifier: nil, animations: nil, transitions: nil, alpha: 1)
set { objc_setAssociatedObject(self, &AssociatedKeys.motionEnabled, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
} }
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceKey, value: value)
}
}
/// A boolean that indicates whether motion is enabled.
@IBInspectable
public var isMotionEnabled: Bool {
get {
return motionInstance.isEnabled
}
set(value) {
motionInstance.isEnabled = value
}
}
/// An identifier value used to connect views across UIViewControllers.
@IBInspectable
open var motionIdentifier: String? {
get {
return motionInstance.identifier
}
set(value) {
motionInstance.identifier = value
}
}
/// The animations to run.
open var motionAnimations: [MotionAnimation]? {
get {
return motionInstance.animations
}
set(value) {
motionInstance.animations = value
}
}
/// The animations to run while in transition.
open var motionTransitions: [MotionTransition]? {
get {
return motionInstance.transitions
}
set(value) {
motionInstance.transitions = value
}
}
/// The animations to run while in transition.
@IBInspectable
open var motionAlpha: CGFloat? {
get {
return motionInstance.alpha
}
set(value) {
motionInstance.alpha = value
}
}
}
/** public extension UIView {
Use **motionModifiers** to specify animations alongside the main transition. Checkout `MotionTransition.swift` for available modifiers.
*/
public var motionModifiers: [MotionTransition]? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionModifiers) as? [MotionTransition] }
set { objc_setAssociatedObject(self, &AssociatedKeys.motionModifiers, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
/** /**
**motionModifierString** provides another way to set **motionModifiers**. It can be assigned through storyboard. **motionModifierString** provides another way to set **motionTransitions**. It can be assigned through storyboard.
*/ */
@IBInspectable public var motionModifierString: String? { @IBInspectable public var motionModifierString: String? {
get { fatalError("Reverse lookup is not supported") } get { fatalError("Reverse lookup is not supported") }
set { motionModifiers = newValue?.parse() } set { motionTransitions = newValue?.parse() }
} }
internal func slowSnapshotView() -> UIView { internal func slowSnapshotView() -> UIView {
...@@ -117,54 +169,6 @@ public extension UIView { ...@@ -117,54 +169,6 @@ public extension UIView {
} }
return isHidden && (superview is UICollectionView || self is UITableViewCell) ? [] : ([self] + subviews.flatMap { $0.flattenedViewHierarchy }) return isHidden && (superview is UICollectionView || self is UITableViewCell) ? [] : ([self] + subviews.flatMap { $0.flattenedViewHierarchy })
} }
/// Used for .overFullScreen presentation
internal var motionStoredAlpha: CGFloat? {
get {
if let doubleValue = (objc_getAssociatedObject(self, &AssociatedKeys.motionStoredAlpha) as? NSNumber)?.doubleValue {
return CGFloat(doubleValue)
}
return nil
}
set {
if let newValue = newValue {
objc_setAssociatedObject(self, &AssociatedKeys.motionStoredAlpha, NSNumber(value:newValue.native), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
} else {
objc_setAssociatedObject(self, &AssociatedKeys.motionStoredAlpha, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
fileprivate var MotionInstanceKey: UInt8 = 0
fileprivate struct MotionInstance {
/// 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(animations: nil)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceKey, value: value)
}
}
/// The animations to run.
open var motionAnimations: [MotionAnimation]? {
get {
return motionInstance.animations
}
set(value) {
motionInstance.animations = value
}
}
} }
extension UIView { extension UIView {
......
...@@ -111,7 +111,7 @@ public extension Motion { ...@@ -111,7 +111,7 @@ public extension Motion {
} }
/// Set the default animation for next transition /// Set the default animation for next transition
/// This usually overrides rootView's motionModifiers during the transition /// This usually overrides rootView's motionTransitions during the transition
/// ///
/// - Parameter animation: animation type /// - Parameter animation: animation type
func setDefaultAnimationForNextTransition(_ animation: MotionDefaultAnimationType) { func setDefaultAnimationForNextTransition(_ animation: MotionDefaultAnimationType) {
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
import UIKit import UIKit
public class MotionContext { public class MotionContext {
internal var motionIDToSourceView = [String: UIView]() internal var motionIdentifierToSourceView = [String: UIView]()
internal var motionIDToDestinationView = [String: UIView]() internal var motionIdentifierToDestinationView = [String: UIView]()
internal var snapshotViews = [UIView: UIView]() internal var snapshotViews = [UIView: UIView]()
internal var viewAlphas = [UIView: CGFloat]() internal var viewAlphas = [UIView: CGFloat]()
internal var targetStates = [UIView: MotionTargetState]() internal var targetStates = [UIView: MotionTargetState]()
...@@ -45,18 +45,18 @@ public class MotionContext { ...@@ -45,18 +45,18 @@ public class MotionContext {
internal func set(fromViews: [UIView], toViews: [UIView]) { internal func set(fromViews: [UIView], toViews: [UIView]) {
self.fromViews = fromViews self.fromViews = fromViews
self.toViews = toViews self.toViews = toViews
process(views: fromViews, idMap: &motionIDToSourceView) process(views: fromViews, idMap: &motionIdentifierToSourceView)
process(views: toViews, idMap: &motionIDToDestinationView) process(views: toViews, idMap: &motionIdentifierToDestinationView)
} }
internal func process(views: [UIView], idMap: inout [String: UIView]) { internal func process(views: [UIView], idMap: inout [String: UIView]) {
for view in views { for view in views {
view.layer.removeAllAnimations() view.layer.removeAllAnimations()
if container.convert(view.bounds, from: view).intersects(container.bounds) { if container.convert(view.bounds, from: view).intersects(container.bounds) {
if let motionID = view.motionID { if let motionIdentifier = view.motionIdentifier {
idMap[motionID] = view idMap[motionIdentifier] = view
} }
if let modifiers = view.motionModifiers { if let modifiers = view.motionTransitions {
targetStates[view] = MotionTargetState(modifiers: modifiers) targetStates[view] = MotionTargetState(modifiers: modifiers)
} }
} }
...@@ -83,24 +83,24 @@ public class MotionContext { ...@@ -83,24 +83,24 @@ public class MotionContext {
extension MotionContext { extension MotionContext {
/** /**
- Returns: a source view matching the motionID, nil if not found - Returns: a source view matching the motionIdentifier, nil if not found
*/ */
public func sourceView(for motionID: String) -> UIView? { public func sourceView(for motionIdentifier: String) -> UIView? {
return motionIDToSourceView[motionID] return motionIdentifierToSourceView[motionIdentifier]
} }
/** /**
- Returns: a destination view matching the motionID, nil if not found - Returns: a destination view matching the motionIdentifier, nil if not found
*/ */
public func destinationView(for motionID: String) -> UIView? { public func destinationView(for motionIdentifier: String) -> UIView? {
return motionIDToDestinationView[motionID] return motionIdentifierToDestinationView[motionIdentifier]
} }
/** /**
- Returns: a view with the same motionID, but on different view controller, nil if not found - Returns: a view with the same motionIdentifier, but on different view controller, nil if not found
*/ */
public func pairedView(for view: UIView) -> UIView? { public func pairedView(for view: UIView) -> UIView? {
if let id = view.motionID { if let id = view.motionIdentifier {
if sourceView(for: id) == view { if sourceView(for: id) == view {
return destinationView(for: id) return destinationView(for: id)
} else if destinationView(for: id) == view { } else if destinationView(for: id) == view {
...@@ -237,7 +237,7 @@ extension MotionContext { ...@@ -237,7 +237,7 @@ extension MotionContext {
} }
snapshot.frame = containerView.convert(view.bounds, from: view) snapshot.frame = containerView.convert(view.bounds, from: view)
snapshot.motionID = view.motionID snapshot.motionIdentifier = view.motionIdentifier
hide(view: view) hide(view: view)
...@@ -352,16 +352,16 @@ extension MotionContext { ...@@ -352,16 +352,16 @@ extension MotionContext {
return snapshots return snapshots
} }
internal func loadViewAlpha(rootView: UIView) { internal func loadViewAlpha(rootView: UIView) {
if let storedAlpha = rootView.motionStoredAlpha { if let storedAlpha = rootView.motionAlpha {
rootView.alpha = storedAlpha rootView.alpha = storedAlpha
rootView.motionStoredAlpha = nil rootView.motionAlpha = nil
} }
for subview in rootView.subviews { for subview in rootView.subviews {
loadViewAlpha(rootView: subview) loadViewAlpha(rootView: subview)
} }
} }
internal func storeViewAlpha(rootView: UIView) { internal func storeViewAlpha(rootView: UIView) {
rootView.motionStoredAlpha = viewAlphas[rootView] rootView.motionAlpha = viewAlphas[rootView]
for subview in rootView.subviews { for subview in rootView.subviews {
storeViewAlpha(rootView: subview) storeViewAlpha(rootView: subview)
} }
......
...@@ -102,8 +102,8 @@ extension MotionTransition: MotionStringConvertible { ...@@ -102,8 +102,8 @@ extension MotionTransition: MotionStringConvertible {
} }
return .cascade(delta: parameters.getDouble(0) ?? 0.02, direction: cascadeDirection, delayMatchedViews:parameters.getBool(2) ?? false) return .cascade(delta: parameters.getDouble(0) ?? 0.02, direction: cascadeDirection, delayMatchedViews:parameters.getBool(2) ?? false)
case "source": case "source":
if let motionID = parameters.get(0)?.name { if let motionIdentifier = parameters.get(0)?.name {
return .source(motionID: motionID) return .source(motionIdentifier: motionIdentifier)
} }
case "useGlobalCoordinateSpace": case "useGlobalCoordinateSpace":
return .useGlobalCoordinateSpace return .useGlobalCoordinateSpace
......
...@@ -408,7 +408,7 @@ extension MotionTransition { ...@@ -408,7 +408,7 @@ extension MotionTransition {
// other modifiers // other modifiers
extension MotionTransition { extension MotionTransition {
/** /**
Transition from/to the state of the view with matching motionID Transition from/to the state of the view with matching motionIdentifier
Will also force the view to use global coordinate space. Will also force the view to use global coordinate space.
The following layer properties will be animated from the given view. The following layer properties will be animated from the given view.
...@@ -430,11 +430,11 @@ extension MotionTransition { ...@@ -430,11 +430,11 @@ extension MotionTransition {
borderColor borderColor
- Parameters: - Parameters:
- motionID: the source view's motionId. - motionIdentifier: the source view's motionId.
*/ */
public static func source(motionID: String) -> MotionTransition { public static func source(motionIdentifier: String) -> MotionTransition {
return MotionTransition { targetState in return MotionTransition { targetState in
targetState.source = motionID targetState.source = motionIdentifier
} }
} }
...@@ -531,12 +531,12 @@ extension MotionTransition { ...@@ -531,12 +531,12 @@ extension MotionTransition {
} }
/** /**
ignore all motionModifiers attributes for a view's direct subviews. ignore all motionTransitions attributes for a view's direct subviews.
*/ */
public static var ignoreSubviewModifiers: MotionTransition = .ignoreSubviewModifiers() public static var ignoreSubviewModifiers: MotionTransition = .ignoreSubviewModifiers()
/** /**
ignore all motionModifiers attributes for a view's subviews. ignore all motionTransitions attributes for a view's subviews.
- Parameters: - Parameters:
- recursive: if false, will only ignore direct subviews' modifiers. default false. - recursive: if false, will only ignore direct subviews' modifiers. default false.
*/ */
......
...@@ -31,7 +31,7 @@ import UIKit ...@@ -31,7 +31,7 @@ import UIKit
class MatchPreprocessor: BasePreprocessor { class MatchPreprocessor: BasePreprocessor {
override func process(fromViews: [UIView], toViews: [UIView]) { override func process(fromViews: [UIView], toViews: [UIView]) {
for tv in toViews { for tv in toViews {
guard let id = tv.motionID, let fv = context.sourceView(for: id) else { continue } guard let id = tv.motionIdentifier, let fv = context.sourceView(for: id) else { continue }
var tvState = context[tv] ?? MotionTargetState() var tvState = context[tv] ?? MotionTargetState()
var fvState = context[fv] ?? MotionTargetState() var fvState = context[fv] ?? MotionTargetState()
......
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