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>]()
/**
Subscript for matching keys and returning the corresponding set.
- Parameter key: A Key type.
- Returns: A Set<Value> type.
*/
subscript(key: Key) -> Set<Value> {
mutating get { mutating get {
if dict[key] == nil { if nil == dictionary[key] {
dict[key] = Set<Value>() dictionary[key] = Set<Value>()
} }
return dict[key]!
return dictionary[key]!
} }
set { set(value) {
dict[key] = newValue dictionary[key] = value
} }
} }
} }
...@@ -49,81 +57,91 @@ internal extension CGSize { ...@@ -49,81 +57,91 @@ 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 { internal var point: CGPoint {
return CGPoint(x: width, y: height) return CGPoint(x: width, y: height)
} }
internal func transform(_ t: CGAffineTransform) -> CGSize { internal func transform(_ t: CGAffineTransform) -> CGSize {
return self.applying(t) return applying(t)
} }
internal func transform(_ t: CATransform3D) -> CGSize { internal func transform(_ t: CATransform3D) -> CGSize {
return self.applying(CATransform3DGetAffineTransform(t)) 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 {
var bounds: CGRect {
return CGRect(origin: CGPoint.zero, size: size) return CGRect(origin: CGPoint.zero, size: size)
} }
init(center: CGPoint, size: CGSize) { 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) 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 { internal extension CGPoint {
return CGPoint(x: self.x+dx, y: self.y+dy) func translate(_ dx: CGFloat, dy: CGFloat) -> CGPoint {
return CGPoint(x: x + dx, y: y + dy)
} }
internal func transform(_ t: CGAffineTransform) -> CGPoint { func transform(_ t: CGAffineTransform) -> CGPoint {
return self.applying(t) return applying(t)
} }
internal func transform(_ t: CATransform3D) -> CGPoint { func transform(_ t: CATransform3D) -> CGPoint {
return self.applying(CATransform3DGetAffineTransform(t)) return applying(CATransform3DGetAffineTransform(t))
} }
internal func distance(_ b: CGPoint) -> CGFloat { func distance(_ b: CGPoint) -> CGFloat {
return sqrt(pow(self.x - b.x, 2) + pow(self.y - b.y, 2)) 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 {
internal func *(left: CGFloat, right: CGPoint) -> CGPoint {
return right * left 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
} }
...@@ -131,14 +149,16 @@ internal func abs(_ p: CGPoint) -> CGPoint { ...@@ -131,14 +149,16 @@ 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 {
......
/*
* 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" fileprivate struct MotionInstance {
static var motionModifiers = "motionModifers" /// A boolean indicating whether Motion is enabled.
static var motionStoredAlpha = "motionStoredAlpha" fileprivate var isEnabled: Bool
static var motionEnabled = "motionEnabled"
/// An optional reference to the motion identifier.
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 {
/// MotionInstance reference.
fileprivate var motionInstance: MotionInstance {
get {
return AssociatedObject.get(base: self, key: &MotionInstanceKey) {
return MotionInstance(isEnabled: true, identifier: nil, animations: nil, transitions: nil, alpha: 1)
}
}
set(value) {
AssociatedObject.set(base: self, key: &MotionInstanceKey, value: value)
}
} }
/** /// A boolean that indicates whether motion is enabled.
**motionID** is the identifier for the view. When doing a transition between two view controllers, @IBInspectable
Motion will search through all the subviews for both view controllers and matches views with the same **motionID**. public var isMotionEnabled: Bool {
get {
return motionInstance.isEnabled
}
set(value) {
motionInstance.isEnabled = value
}
}
Whenever a pair is discovered, /// An identifier value used to connect views across UIViewControllers.
Motion will automatically transit the views from source state to the destination state. @IBInspectable
*/ open var motionIdentifier: String? {
@IBInspectable public var motionID: String? { get {
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionID) as? String } return motionInstance.identifier
set { objc_setAssociatedObject(self, &AssociatedKeys.motionID, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
set(value) {
motionInstance.identifier = value
}
} }
/** /// The animations to run.
**isMotionEnabled** allows to specify whether a view and its subviews should be consider for animations. open var motionAnimations: [MotionAnimation]? {
If true, Motion will search through all the subviews for motionIds and modifiers. Defaults to true get {
*/ return motionInstance.animations
@IBInspectable public var isMotionEnabled: Bool { }
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionEnabled) as? Bool ?? true } set(value) {
set { objc_setAssociatedObject(self, &AssociatedKeys.motionEnabled, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } motionInstance.animations = value
}
} }
/** /// The animations to run while in transition.
Use **motionModifiers** to specify animations alongside the main transition. Checkout `MotionTransition.swift` for available modifiers. open var motionTransitions: [MotionTransition]? {
*/ get {
public var motionModifiers: [MotionTransition]? { return motionInstance.transitions
get { return objc_getAssociatedObject(self, &AssociatedKeys.motionModifiers) as? [MotionTransition] } }
set { objc_setAssociatedObject(self, &AssociatedKeys.motionModifiers, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } 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 {
/** /**
**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