Commit 91591377 by Daniel Dahan

development: added Motion to Material

parent f5c3ef6c
/*
* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
@objc(AnimationFillMode)
public enum AnimationFillMode: Int {
case forwards
case backwards
case both
case removed
}
/**
Converts the AnimationFillMode enum value to a corresponding String.
- Parameter mode: An AnimationFillMode enum value.
*/
public func AnimationFillModeToValue(mode: AnimationFillMode) -> String {
switch mode {
case .forwards:
return kCAFillModeForwards
case .backwards:
return kCAFillModeBackwards
case .both:
return kCAFillModeBoth
case .removed:
return kCAFillModeRemoved
}
}
@objc(AnimationTimingFunction)
public enum AnimationTimingFunction: Int {
case `default`
case linear
case easeIn
case easeOut
case easeInEaseOut
}
/**
Converts the AnimationTimingFunction enum value to a corresponding CAMediaTimingFunction.
- Parameter function: An AnimationTimingFunction enum value.
- Returns: A CAMediaTimingFunction.
*/
public func AnimationTimingFunctionToValue(function: AnimationTimingFunction) -> CAMediaTimingFunction {
switch function {
case .default:
return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
case .linear:
return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
case .easeIn:
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
case .easeOut:
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
case .easeInEaseOut:
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
}
}
public typealias AnimationDelayCancelBlock = (Bool) -> Void
public struct Animation {
/**
Executes a block of code after a time delay.
- Parameter duration: An animation duration time.
- Parameter animations: An animation block.
- Parameter execute block: A completion block that is executed once
the animations have completed.
*/
@discardableResult
public static func delay(_ time: TimeInterval, execute block: @escaping () -> Void) -> AnimationDelayCancelBlock? {
func asyncAfter(completion: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time, execute: completion)
}
var cancelable: AnimationDelayCancelBlock?
let delayed: AnimationDelayCancelBlock = {
if !$0 {
DispatchQueue.main.async(execute: block)
}
cancelable = nil
}
cancelable = delayed
asyncAfter {
cancelable?(false)
}
return cancelable;
}
/**
Cancels the delayed AnimationDelayCancelBlock.
- Parameter delayed completion: An AnimationDelayCancelBlock.
*/
public static func cancel(delayed completion: AnimationDelayCancelBlock) {
completion(true)
}
/**
Disables the default animations set on CALayers.
- Parameter animations: A callback that wraps the animations to disable.
*/
public static func disable(animations: (() -> Void)) {
animate(duration: 0, animations: animations)
}
/**
Runs an animation with a specified duration.
- Parameter duration: An animation duration time.
- Parameter animations: An animation block.
- Parameter timingFunction: An AnimationTimingFunction value.
- Parameter completion: A completion block that is executed once
the animations have completed.
*/
public static func animate(duration: CFTimeInterval, timingFunction: AnimationTimingFunction = .easeInEaseOut, animations: (() -> Void), completion: (() -> Void)? = nil) {
CATransaction.begin()
CATransaction.setAnimationDuration(duration)
CATransaction.setCompletionBlock(completion)
CATransaction.setAnimationTimingFunction(AnimationTimingFunctionToValue(function: .easeInEaseOut))
animations()
CATransaction.commit()
}
/**
Creates a CAAnimationGroup.
- Parameter animations: An Array of CAAnimation objects.
- Parameter timingFunction: An AnimationTimingFunction value.
- Parameter duration: An animation duration time for the group.
- Returns: A CAAnimationGroup.
*/
public static func animate(group animations: [CAAnimation], timingFunction: AnimationTimingFunction = .easeInEaseOut, duration: CFTimeInterval = 0.5) -> CAAnimationGroup {
let group = CAAnimationGroup()
group.fillMode = AnimationFillModeToValue(mode: .forwards)
group.isRemovedOnCompletion = false
group.animations = animations
group.duration = duration
group.timingFunction = AnimationTimingFunctionToValue(function: timingFunction)
return group
}
/**
Executes an animation block with a given delay and duration.
- Parameter delay time: A CFTimeInterval.
- Parameter duration: An animation duration time.
- Parameter animations: An animation block.
- Parameter completion: A completion block that is executed once
the animations have completed.
*/
public static func animate(delay time: CFTimeInterval, duration: CFTimeInterval, animations: @escaping (() -> Void), completion: (() -> Void)? = nil) {
delay(time) {
animate(duration: duration, animations: animations, completion: completion)
}
}
}
/*
* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
public enum AnimationKeyPath: String {
case backgroundColor
case scale = "transform.scale"
case position
case shadowPath
}
extension CABasicAnimation {
/**
A convenience initializer that takes a given AnimationKeyPath.
- Parameter keyPath: An AnimationKeyPath.
*/
public convenience init(keyPath: AnimationKeyPath) {
self.init(keyPath: keyPath.rawValue)
}
}
extension Animation {
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Parameter duration: An animation time duration.
- Returns: A CABasicAnimation.
*/
public static func backgroundColor(color: UIColor, duration: CFTimeInterval? = nil) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .backgroundColor)
animation.toValue = color.cgColor
animation.fillMode = AnimationFillModeToValue(mode: .forwards)
animation.isRemovedOnCompletion = false
animation.timingFunction = AnimationTimingFunctionToValue(function: .easeInEaseOut)
if let v = duration {
animation.duration = v
}
return animation
}
/**
Creates a CABasicAnimation for the transform.scale key path.
- Parameter by scale: A CGFloat.
- Parameter duration: An animation time duration.
- Returns: A CABasicAnimation.
*/
public static func scale(by scale: CGFloat, duration: CFTimeInterval? = nil) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .scale)
animation.toValue = scale as NSNumber
animation.fillMode = AnimationFillModeToValue(mode: .forwards)
animation.isRemovedOnCompletion = false
animation.timingFunction = AnimationTimingFunctionToValue(function: .easeInEaseOut)
if let v = duration {
animation.duration = v
}
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter to point: A CGPoint.
- Parameter duration: An animation time duration.
- Returns: A CABasicAnimation.
*/
public static func position(to point: CGPoint, duration: CFTimeInterval? = nil) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: point)
animation.fillMode = AnimationFillModeToValue(mode: .forwards)
animation.isRemovedOnCompletion = false
animation.timingFunction = AnimationTimingFunctionToValue(function: .easeInEaseOut)
if let v = duration {
animation.duration = v
}
return animation
}
/**
Creates a CABasicAnimation for the shadowPath key path.
- Parameter to path: A CGPath.
- Parameter duration: An animation time duration.
- Returns: A CABasicAnimation.
*/
public static func shadowPath(to path: CGPath, duration: CFTimeInterval? = nil) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .shadowPath)
animation.toValue = path
animation.fillMode = AnimationFillModeToValue(mode: .forwards)
animation.isRemovedOnCompletion = false
animation.timingFunction = AnimationTimingFunctionToValue(function: .linear)
if let v = duration {
animation.duration = v
}
return animation
}
}
...@@ -42,6 +42,11 @@ open class Button: UIButton, Pulseable { ...@@ -42,6 +42,11 @@ open class Button: UIButton, Pulseable {
/// A Pulse reference. /// A Pulse reference.
internal var pulse: Pulse! internal var pulse: Pulse!
/// A reference to the pulse layer.
public var pulseLayer: CALayer? {
return pulse.pulseLayer
}
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
get { get {
...@@ -189,7 +194,7 @@ open class Button: UIButton, Pulseable { ...@@ -189,7 +194,7 @@ open class Button: UIButton, Pulseable {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
pulse.expand(point: point ?? center) pulse.expand(point: point ?? center)
Animation.delay(0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -43,6 +43,11 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable { ...@@ -43,6 +43,11 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable {
/// A Pulse reference. /// A Pulse reference.
internal var pulse: Pulse! internal var pulse: Pulse!
/// A reference to the pulse layer.
public var pulseLayer: CALayer? {
return pulse.pulseLayer
}
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
get { get {
...@@ -241,7 +246,7 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable { ...@@ -241,7 +246,7 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
pulse.expand(point: point ?? center) pulse.expand(point: point ?? center)
Animation.delay(0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -43,6 +43,11 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable { ...@@ -43,6 +43,11 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable {
/// A Pulse reference. /// A Pulse reference.
internal var pulse: Pulse! internal var pulse: Pulse!
/// A reference to the pulse layer.
public var pulseLayer: CALayer? {
return pulse.pulseLayer
}
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
get { get {
...@@ -199,7 +204,7 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable { ...@@ -199,7 +204,7 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
pulse.expand(point: point ?? center) pulse.expand(point: point ?? center)
Animation.delay(0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -248,63 +248,6 @@ extension CALayer { ...@@ -248,63 +248,6 @@ extension CALayer {
} }
extension CALayer { extension CALayer {
/**
A method that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open func animate(_ animation: CAAnimation) {
animation.delegate = self
if let a = animation as? CABasicAnimation {
a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!)
}
if let a = animation as? CAPropertyAnimation {
add(a, forKey: a.keyPath!)
} else if let a = animation as? CAAnimationGroup {
add(a, forKey: nil)
} else if let a = animation as? CATransition {
add(a, forKey: kCATransition)
}
}
/**
A delegation method that is executed when the backing layer stops
running an animation.
- Parameter animation: The CAAnimation instance that stopped running.
- Parameter flag: A boolean that indicates if the animation stopped
because it was completed or interrupted. True if completed, false
if interrupted.
*/
open func animationDidStop(_ animation: CAAnimation, finished flag: Bool) {
guard let a = animation as? CAPropertyAnimation else {
if let a = (animation as? CAAnimationGroup)?.animations {
for x in a {
animationDidStop(x, finished: true)
}
}
return
}
guard let b = a as? CABasicAnimation else {
return
}
guard let v = b.toValue else {
return
}
guard let k = b.keyPath else {
return
}
setValue(v, forKeyPath: k)
removeAnimation(forKey: k)
}
}
extension CALayer {
/// Manages the layout for the shape of the view instance. /// Manages the layout for the shape of the view instance.
open func layoutShape() { open func layoutShape() {
guard .none != shapePreset else { guard .none != shapePreset else {
...@@ -337,12 +280,7 @@ extension CALayer { ...@@ -337,12 +280,7 @@ extension CALayer {
} else if nil == shadowPath { } else if nil == shadowPath {
shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
} else { } else {
let a = Animation.shadowPath(to: UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath) motion(.shadow(path: UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath))
a.fromValue = shadowPath
animate(a)
} }
} }
} }
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
...@@ -93,6 +93,9 @@ public enum MotionAnimation { ...@@ -93,6 +93,9 @@ public enum MotionAnimation {
case size(width: CGFloat, height: CGFloat) case size(width: CGFloat, height: CGFloat)
} }
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
extension CALayer { extension CALayer {
/** /**
...@@ -111,7 +114,10 @@ extension CALayer { ...@@ -111,7 +114,10 @@ extension CALayer {
*/ */
open func animate(_ animations: [CAAnimation]) { open func animate(_ animations: [CAAnimation]) {
for animation in animations { for animation in animations {
animation.delegate = self if nil == animation.delegate {
animation.delegate = self
}
if let a = animation as? CABasicAnimation { if let a = animation as? CABasicAnimation {
a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!) a.fromValue = (presentation() ?? self).value(forKeyPath: a.keyPath!)
} }
...@@ -126,6 +132,8 @@ extension CALayer { ...@@ -126,6 +132,8 @@ extension CALayer {
} }
} }
open func animationDidStart(_ anim: CAAnimation) {}
/** /**
A delegation function that is executed when the backing layer stops A delegation function that is executed when the backing layer stops
running an animation. running an animation.
...@@ -134,9 +142,9 @@ extension CALayer { ...@@ -134,9 +142,9 @@ extension CALayer {
because it was completed or interrupted. True if completed, false because it was completed or interrupted. True if completed, false
if interrupted. if interrupted.
*/ */
open func animationDidStop(_ animation: CAAnimation, finished flag: Bool) { open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
guard let a = animation as? CAPropertyAnimation else { guard let a = anim as? CAPropertyAnimation else {
if let a = (animation as? CAAnimationGroup)?.animations { if let a = (anim as? CAAnimationGroup)?.animations {
for x in a { for x in a {
animationDidStop(x, finished: true) animationDidStop(x, finished: true)
} }
...@@ -173,7 +181,7 @@ extension CALayer { ...@@ -173,7 +181,7 @@ extension CALayer {
- Parameter animations: An Array of MotionAnimation values. - Parameter animations: An Array of MotionAnimation values.
*/ */
open func motion(_ animations: [MotionAnimation]) { open func motion(_ animations: [MotionAnimation]) {
motion(delay: 0, duration: 0.25, timingFunction: .easeInEaseOut, animations: animations) motion(delay: 0, duration: 0.35, timingFunction: .easeInEaseOut, animations: animations)
} }
/** /**
...@@ -315,9 +323,6 @@ extension CALayer { ...@@ -315,9 +323,6 @@ extension CALayer {
} }
} }
@available(iOS 10, *)
extension CALayer: CAAnimationDelegate {}
extension UIView { extension UIView {
/// Computes the rotation of the view. /// Computes the rotation of the view.
open var motionRotationAngle: CGFloat { open var motionRotationAngle: CGFloat {
...@@ -331,7 +336,7 @@ extension UIView { ...@@ -331,7 +336,7 @@ extension UIView {
/// The global position of a view. /// The global position of a view.
open var motionPosition: CGPoint { open var motionPosition: CGPoint {
return superview?.convert(position, to: nil) ?? position return superview?.convert(layer.position, to: nil) ?? layer.position
} }
/// The layer.transform of a view. /// The layer.transform of a view.
......
...@@ -51,6 +51,9 @@ public protocol Pulseable { ...@@ -51,6 +51,9 @@ public protocol Pulseable {
/// The opcaity value for the pulse animation. /// The opcaity value for the pulse animation.
var pulseOpacity: CGFloat { get set } var pulseOpacity: CGFloat { get set }
/// A reference to the pulse layer.
var pulseLayer: CALayer? { get }
} }
public struct Pulse { public struct Pulse {
...@@ -58,7 +61,7 @@ public struct Pulse { ...@@ -58,7 +61,7 @@ public struct Pulse {
fileprivate weak var pulseView: UIView? fileprivate weak var pulseView: UIView?
/// The layer the pulse layers are added to. /// The layer the pulse layers are added to.
fileprivate weak var pulseLayer: CALayer? internal weak var pulseLayer: CALayer?
/// Pulse layers. /// Pulse layers.
fileprivate var layers = [CAShapeLayer]() fileprivate var layers = [CAShapeLayer]()
...@@ -114,7 +117,7 @@ public struct Pulse { ...@@ -114,7 +117,7 @@ public struct Pulse {
let w = view.bounds.width let w = view.bounds.width
let h = view.bounds.height let h = view.bounds.height
Animation.disable(animations: { [ Motion.disable({ [
n = .center == animation ? w < h ? w : h : w < h ? h : w, n = .center == animation ? w < h ? w : h : w < h ? h : w,
bounds = layer.bounds, bounds = layer.bounds,
animation = animation, animation = animation,
...@@ -143,17 +146,17 @@ public struct Pulse { ...@@ -143,17 +146,17 @@ public struct Pulse {
switch animation { switch animation {
case .centerWithBacking, .backing, .pointWithBacking: case .centerWithBacking, .backing, .pointWithBacking:
bLayer.add(Animation.backgroundColor(color: color.withAlphaComponent(opacity / 2), duration: duration), forKey: nil) bLayer.motion(.backgroundColor(color.withAlphaComponent(opacity / 2)), .duration(duration))
default:break default:break
} }
switch animation { switch animation {
case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking: case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking:
pLayer.add(Animation.scale(by: 1, duration: duration), forKey: nil) pLayer.motion(.scale(1), .duration(duration))
default:break default:break
} }
Animation.delay(duration) { Motion.delay(duration) {
bLayer.setValue(true, forKey: "animated") bLayer.setValue(true, forKey: "animated")
} }
} }
...@@ -168,7 +171,7 @@ public struct Pulse { ...@@ -168,7 +171,7 @@ public struct Pulse {
return return
} }
Animation.delay(animated ? 0 : 0.15) { [animation = animation, color = color] in Motion.delay(animated ? 0 : 0.15) { [animation = animation, color = color] in
guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else { guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else {
return return
} }
...@@ -177,20 +180,17 @@ public struct Pulse { ...@@ -177,20 +180,17 @@ public struct Pulse {
switch animation { switch animation {
case .centerWithBacking, .backing, .pointWithBacking: case .centerWithBacking, .backing, .pointWithBacking:
bLayer.add(Animation.backgroundColor(color: color.withAlphaComponent(0), duration: duration), forKey: nil) bLayer.motion(.backgroundColor(color.withAlphaComponent(0)), .duration(duration))
default:break default:break
} }
switch animation { switch animation {
case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking: case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking:
pLayer.add(Animation.animate(group: [ pLayer.motion(.scale(.center == animation ? 1 : 1.325), .backgroundColor(color.withAlphaComponent(0)))
Animation.scale(by: .center == animation ? 1 : 1.325),
Animation.backgroundColor(color: color.withAlphaComponent(0))
], duration: duration), forKey: nil)
default:break default:break
} }
Animation.delay(duration) { Motion.delay(duration) {
pLayer.removeFromSuperlayer() pLayer.removeFromSuperlayer()
bLayer.removeFromSuperlayer() bLayer.removeFromSuperlayer()
} }
......
...@@ -34,6 +34,11 @@ open class PulseView: View, Pulseable { ...@@ -34,6 +34,11 @@ open class PulseView: View, Pulseable {
/// A Pulse reference. /// A Pulse reference.
internal var pulse: Pulse! internal var pulse: Pulse!
/// A reference to the pulse layer.
public var pulseLayer: CALayer? {
return pulse.pulseLayer
}
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
get { get {
...@@ -73,7 +78,7 @@ open class PulseView: View, Pulseable { ...@@ -73,7 +78,7 @@ open class PulseView: View, Pulseable {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
pulse.expand(point: point ?? center) pulse.expand(point: point ?? center)
Animation.delay(0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -122,8 +122,8 @@ open class SnackbarController: RootController { ...@@ -122,8 +122,8 @@ open class SnackbarController: RootController {
- Parameter status: A SnackbarStatus enum value. - Parameter status: A SnackbarStatus enum value.
*/ */
@discardableResult @discardableResult
open func animate(snackbar status: SnackbarStatus, delay: TimeInterval = 0, animations: ((Snackbar) -> Void)? = nil, completion: ((Snackbar) -> Void)? = nil) -> AnimationDelayCancelBlock? { open func animate(snackbar status: SnackbarStatus, delay: TimeInterval = 0, animations: ((Snackbar) -> Void)? = nil, completion: ((Snackbar) -> Void)? = nil) -> MotionDelayCancelBlock? {
return Animation.delay(delay) { [weak self, status = status, animations = animations, completion = completion] in return Motion.delay(delay) { [weak self, status = status, animations = animations, completion = completion] in
guard let s = self else { guard let s = self else {
return return
} }
......
...@@ -42,6 +42,11 @@ open class TableViewCell: UITableViewCell, Pulseable { ...@@ -42,6 +42,11 @@ open class TableViewCell: UITableViewCell, Pulseable {
/// A Pulse reference. /// A Pulse reference.
internal var pulse: Pulse! internal var pulse: Pulse!
/// A reference to the pulse layer.
public var pulseLayer: CALayer? {
return pulse.pulseLayer
}
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
get { get {
...@@ -115,7 +120,7 @@ open class TableViewCell: UITableViewCell, Pulseable { ...@@ -115,7 +120,7 @@ open class TableViewCell: UITableViewCell, Pulseable {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
pulse.expand(point: point ?? center) pulse.expand(point: point ?? center)
Animation.delay(0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
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