Commit 062c21f8 by Daniel Dahan

editor: issue-588: removing Pulse animation memory leaks

parent f7dbffeb
...@@ -30,17 +30,17 @@ ...@@ -30,17 +30,17 @@
import UIKit import UIKit
open class Button: UIButton { open class Button: UIButton, Pulsable {
/** /**
A CAShapeLayer used to manage elements that would be affected by A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this the clipToBounds property of the backing layer. For example, this
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open private(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/// A Pulse reference. /// A Pulse reference.
internal private(set) lazy var pulse: Pulse = Pulse() internal internal(set) lazy var pulse: Pulse = Pulse()
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
...@@ -181,15 +181,15 @@ open class Button: UIButton { ...@@ -181,15 +181,15 @@ open class Button: UIButton {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point! let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point!
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: p, width: width, height: height, pulse: &pulse)
var s = self
MotionPulseAnimation<Button>.pulseExpandAnimation(&s, point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(time: 0.35) { [weak self] in
guard let s = self else { guard var s = self else {
return return
} }
Motion.pulseContractAnimation(layer: s.layer, visualLayer: s.visualLayer, pulse: &s.pulse) MotionPulseAnimation<Button>.pulseContractAnimation(&s)
} }
bringImageViewToFront()
} }
/** /**
...@@ -200,9 +200,8 @@ open class Button: UIButton { ...@@ -200,9 +200,8 @@ open class Button: UIButton {
*/ */
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: layer.convert(touches.first!.location(in: self), from: layer), width: width, height: height, pulse: &pulse) var s = self
MotionPulseAnimation<Button>.pulseExpandAnimation(&s, point: layer.convert(touches.first!.location(in: s), from: layer))
bringImageViewToFront()
} }
/** /**
...@@ -213,7 +212,8 @@ open class Button: UIButton { ...@@ -213,7 +212,8 @@ open class Button: UIButton {
*/ */
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<Button>.pulseContractAnimation(&s)
} }
/** /**
...@@ -224,7 +224,8 @@ open class Button: UIButton { ...@@ -224,7 +224,8 @@ open class Button: UIButton {
*/ */
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<Button>.pulseContractAnimation(&s)
} }
open func bringImageViewToFront() { open func bringImageViewToFront() {
......
...@@ -31,17 +31,17 @@ ...@@ -31,17 +31,17 @@
import UIKit import UIKit
@objc(CollectionReusableView) @objc(CollectionReusableView)
open class CollectionReusableView: UICollectionReusableView { open class CollectionReusableView: UICollectionReusableView, Pulsable {
/** /**
A CAShapeLayer used to manage elements that would be affected by A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this the clipToBounds property of the backing layer. For example, this
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open private(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/// A Pulse reference. /// A Pulse reference.
internal private(set) lazy var pulse: Pulse = Pulse() internal internal(set) lazy var pulse: Pulse = Pulse()
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
...@@ -235,12 +235,14 @@ open class CollectionReusableView: UICollectionReusableView { ...@@ -235,12 +235,14 @@ open class CollectionReusableView: UICollectionReusableView {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point! let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point!
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: p, width: width, height: height, pulse: &pulse)
var s = self
MotionPulseAnimation<CollectionReusableView>.pulseExpandAnimation(&s, point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(time: 0.35) { [weak self] in
guard let s = self else { guard var s = self else {
return return
} }
Motion.pulseContractAnimation(layer: s.layer, visualLayer: s.visualLayer, pulse: &s.pulse) MotionPulseAnimation<CollectionReusableView>.pulseContractAnimation(&s)
} }
} }
...@@ -252,7 +254,8 @@ open class CollectionReusableView: UICollectionReusableView { ...@@ -252,7 +254,8 @@ open class CollectionReusableView: UICollectionReusableView {
*/ */
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: layer.convert(touches.first!.location(in: self), from: layer), width: width, height: height, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionReusableView>.pulseExpandAnimation(&s, point: layer.convert(touches.first!.location(in: s), from: layer))
} }
/** /**
...@@ -263,7 +266,8 @@ open class CollectionReusableView: UICollectionReusableView { ...@@ -263,7 +266,8 @@ open class CollectionReusableView: UICollectionReusableView {
*/ */
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionReusableView>.pulseContractAnimation(&s)
} }
/** /**
...@@ -274,7 +278,8 @@ open class CollectionReusableView: UICollectionReusableView { ...@@ -274,7 +278,8 @@ open class CollectionReusableView: UICollectionReusableView {
*/ */
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionReusableView>.pulseContractAnimation(&s)
} }
/** /**
......
...@@ -31,17 +31,17 @@ ...@@ -31,17 +31,17 @@
import UIKit import UIKit
@objc(CollectionViewCell) @objc(CollectionViewCell)
open class CollectionViewCell: UICollectionViewCell { open class CollectionViewCell: UICollectionViewCell, Pulsable {
/** /**
A CAShapeLayer used to manage elements that would be affected by A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this the clipToBounds property of the backing layer. For example, this
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open private(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/// A Pulse reference. /// A Pulse reference.
internal private(set) lazy var pulse: Pulse = Pulse() internal internal(set) lazy var pulse: Pulse = Pulse()
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
...@@ -242,12 +242,14 @@ open class CollectionViewCell: UICollectionViewCell { ...@@ -242,12 +242,14 @@ open class CollectionViewCell: UICollectionViewCell {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point! let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point!
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: p, width: width, height: height, pulse: &pulse)
var s = self
MotionPulseAnimation<CollectionViewCell>.pulseExpandAnimation(&s, point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(time: 0.35) { [weak self] in
guard let s = self else { guard var s = self else {
return return
} }
Motion.pulseContractAnimation(layer: s.layer, visualLayer: s.visualLayer, pulse: &s.pulse) MotionPulseAnimation<CollectionViewCell>.pulseContractAnimation(&s)
} }
} }
...@@ -259,7 +261,8 @@ open class CollectionViewCell: UICollectionViewCell { ...@@ -259,7 +261,8 @@ open class CollectionViewCell: UICollectionViewCell {
*/ */
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: layer.convert(touches.first!.location(in: self), from: layer), width: width, height: height, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionViewCell>.pulseExpandAnimation(&s, point: layer.convert(touches.first!.location(in: s), from: layer))
} }
/** /**
...@@ -270,7 +273,8 @@ open class CollectionViewCell: UICollectionViewCell { ...@@ -270,7 +273,8 @@ open class CollectionViewCell: UICollectionViewCell {
*/ */
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionViewCell>.pulseContractAnimation(&s)
} }
/** /**
...@@ -281,7 +285,8 @@ open class CollectionViewCell: UICollectionViewCell { ...@@ -281,7 +285,8 @@ open class CollectionViewCell: UICollectionViewCell {
*/ */
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<CollectionViewCell>.pulseContractAnimation(&s)
} }
/** /**
......
...@@ -38,7 +38,7 @@ open class Layer: CAShapeLayer { ...@@ -38,7 +38,7 @@ open class Layer: CAShapeLayer {
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open private(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/** /**
A property that manages an image for the visualLayer's contents A property that manages an image for the visualLayer's contents
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
import UIKit import UIKit
internal class MaterialLayer { internal struct MaterialLayer {
/// A reference to the CALayer. /// A reference to the CALayer.
internal weak var layer: CALayer? internal weak var layer: CALayer?
......
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
import UIKit import UIKit
internal protocol Pulsable {
var pulse: Pulse { get set }
var visualLayer: CAShapeLayer { get set }
}
internal struct Pulse { internal struct Pulse {
/// An Array of layers. /// An Array of layers.
internal lazy var layers = [CAShapeLayer]() internal lazy var layers = [CAShapeLayer]()
......
...@@ -42,62 +42,61 @@ public enum PulseAnimation: Int { ...@@ -42,62 +42,61 @@ public enum PulseAnimation: Int {
case pointWithBacking case pointWithBacking
} }
internal extension Motion { internal struct MotionPulseAnimation<T: UIView> where T: Pulsable {
/** /**
Triggers the expanding animation. Triggers the expanding animation.
- Parameter layer: Container CALayer. - Parameter _ view: A Reference to the view to add the
- Parameter visualLayer: A CAShapeLayer. animations too.
- Parameter point: A point to pulse from. - Parameter point: A point to pulse from.
- Parameter width: Container width.
- Parameter height: Container height.
- Parameter duration: Animation duration.
- Parameter pulse: A Pulse instance.
*/ */
internal static func pulseExpandAnimation(layer: CALayer, visualLayer: CALayer, point: CGPoint, width: CGFloat, height: CGFloat, pulse: inout Pulse) { internal static func pulseExpandAnimation(_ view: inout T, point: CGPoint) {
guard .none != pulse.animation else { guard .none != view.pulse.animation else {
return return
} }
let n = .center == pulse.animation ? width < height ? width : height : width < height ? height : width let w = view.width
let h = view.height
let n = .center == view.pulse.animation ? w < h ? w : h : w < h ? h : w
let bLayer = CAShapeLayer() let bLayer = CAShapeLayer()
let pLayer = CAShapeLayer() let pLayer = CAShapeLayer()
bLayer.addSublayer(pLayer) bLayer.addSublayer(pLayer)
pulse.layers.insert(bLayer, at: 0) view.pulse.layers.insert(bLayer, at: 0)
visualLayer.addSublayer(bLayer) view.visualLayer.addSublayer(bLayer)
bLayer.zPosition = 0 bLayer.zPosition = 0
pLayer.zPosition = 0 pLayer.zPosition = 0
visualLayer.masksToBounds = !(.centerRadialBeyondBounds == pulse.animation || .radialBeyondBounds == pulse.animation) view.visualLayer.masksToBounds = !(.centerRadialBeyondBounds == view.pulse.animation || .radialBeyondBounds == view.pulse.animation)
Motion.disable(animations: { [visualLayer = visualLayer, pulse = pulse] in Motion.disable(animations: { [view = view] in
bLayer.frame = visualLayer.bounds bLayer.frame = view.visualLayer.bounds
pLayer.bounds = CGRect(x: 0, y: 0, width: n, height: n) pLayer.bounds = CGRect(x: 0, y: 0, width: n, height: n)
switch pulse.animation { switch view.pulse.animation {
case .center, .centerWithBacking, .centerRadialBeyondBounds: case .center, .centerWithBacking, .centerRadialBeyondBounds:
pLayer.position = CGPoint(x: width / 2, y: height / 2) pLayer.position = CGPoint(x: w / 2, y: h / 2)
default: default:
pLayer.position = point pLayer.position = point
} }
pLayer.cornerRadius = n / 2 pLayer.cornerRadius = n / 2
pLayer.backgroundColor = pulse.color.withAlphaComponent(pulse.opacity).cgColor pLayer.backgroundColor = view.pulse.color.withAlphaComponent(view.pulse.opacity).cgColor
pLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(scaleX: 0, y: 0)) pLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(scaleX: 0, y: 0))
}) })
bLayer.setValue(false, forKey: "animated") bLayer.setValue(false, forKey: "animated")
let duration: CFTimeInterval = .center == pulse.animation ? 0.16125 : 0.325 let duration: CFTimeInterval = .center == view.pulse.animation ? 0.16125 : 0.325
switch pulse.animation { switch view.pulse.animation {
case .centerWithBacking, .backing, .pointWithBacking: case .centerWithBacking, .backing, .pointWithBacking:
bLayer.add(Motion.backgroundColor(color: pulse.color.withAlphaComponent(pulse.opacity / 2), duration: duration), forKey: nil) bLayer.add(Motion.backgroundColor(color: view.pulse.color.withAlphaComponent(view.pulse.opacity / 2), duration: duration), forKey: nil)
default:break default:break
} }
switch pulse.animation { switch view.pulse.animation {
case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking: case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking:
pLayer.add(Motion.scale(by: 1, duration: duration), forKey: nil) pLayer.add(Motion.scale(by: 1, duration: duration), forKey: nil)
default:break default:break
...@@ -110,12 +109,12 @@ internal extension Motion { ...@@ -110,12 +109,12 @@ internal extension Motion {
/** /**
Triggers the contracting animation. Triggers the contracting animation.
- Parameter layer: Container CALayer. - Parameter _ view: A Reference to the view to add the
- Parameter visualLayer: A CAShapeLayer. animations too.
- Parameter pulse: A Pulse instance. - Parameter pulse: A Pulse instance.
*/ */
internal static func pulseContractAnimation(layer: CALayer, visualLayer: CALayer, pulse: inout Pulse) { internal static func pulseContractAnimation(_ view: inout T) {
guard let bLayer = pulse.layers.popLast() else { guard let bLayer = view.pulse.layers.popLast() else {
return return
} }
...@@ -123,24 +122,24 @@ internal extension Motion { ...@@ -123,24 +122,24 @@ internal extension Motion {
return return
} }
Motion.delay(time: animated ? 0 : 0.15) { [pulse = pulse] in Motion.delay(time: animated ? 0 : 0.15) { [view = view] in
guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else { guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else {
return return
} }
let duration = 0.325 let duration = 0.325
switch pulse.animation { switch view.pulse.animation {
case .centerWithBacking, .backing, .pointWithBacking: case .centerWithBacking, .backing, .pointWithBacking:
bLayer.add(Motion.backgroundColor(color: pulse.color.withAlphaComponent(0), duration: duration), forKey: nil) bLayer.add(Motion.backgroundColor(color: view.pulse.color.withAlphaComponent(0), duration: duration), forKey: nil)
default:break default:break
} }
switch pulse.animation { switch view.pulse.animation {
case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking: case .center, .centerWithBacking, .centerRadialBeyondBounds, .radialBeyondBounds, .point, .pointWithBacking:
pLayer.add(Motion.animate(group: [ pLayer.add(Motion.animate(group: [
Motion.scale(by: .center == pulse.animation ? 1 : 1.325), Motion.scale(by: .center == view.pulse.animation ? 1 : 1.325),
Motion.backgroundColor(color: pulse.color.withAlphaComponent(0)) Motion.backgroundColor(color: view.pulse.color.withAlphaComponent(0))
], duration: duration), forKey: nil) ], duration: duration), forKey: nil)
default:break default:break
} }
......
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
import UIKit import UIKit
open class PulseView: View { open class PulseView: View, Pulsable {
/// A Pulse reference. /// A Pulse reference.
internal private(set) lazy var pulse: Pulse = Pulse() internal internal(set) lazy var pulse: Pulse = Pulse()
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
...@@ -73,12 +73,14 @@ open class PulseView: View { ...@@ -73,12 +73,14 @@ open class PulseView: View {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point! let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point!
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: p, width: width, height: height, pulse: &pulse)
var s = self
MotionPulseAnimation<PulseView>.pulseExpandAnimation(&s, point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(time: 0.35) { [weak self] in
guard let s = self else { guard var s = self else {
return return
} }
Motion.pulseContractAnimation(layer: s.layer, visualLayer: s.visualLayer, pulse: &s.pulse) MotionPulseAnimation<PulseView>.pulseContractAnimation(&s)
} }
} }
...@@ -90,7 +92,8 @@ open class PulseView: View { ...@@ -90,7 +92,8 @@ open class PulseView: View {
*/ */
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: layer.convert(touches.first!.location(in: self), from: layer), width: width, height: height, pulse: &pulse) var s = self
MotionPulseAnimation<PulseView>.pulseExpandAnimation(&s, point: layer.convert(touches.first!.location(in: s), from: layer))
} }
/** /**
...@@ -101,7 +104,8 @@ open class PulseView: View { ...@@ -101,7 +104,8 @@ open class PulseView: View {
*/ */
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<PulseView>.pulseContractAnimation(&s)
} }
/** /**
...@@ -112,6 +116,7 @@ open class PulseView: View { ...@@ -112,6 +116,7 @@ open class PulseView: View {
*/ */
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<PulseView>.pulseContractAnimation(&s)
} }
} }
...@@ -30,17 +30,17 @@ ...@@ -30,17 +30,17 @@
import UIKit import UIKit
open class TableViewCell: UITableViewCell { open class TableViewCell: UITableViewCell, Pulsable {
/** /**
A CAShapeLayer used to manage elements that would be affected by A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this the clipToBounds property of the backing layer. For example, this
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open private(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/// A Pulse reference. /// A Pulse reference.
internal private(set) lazy var pulse: Pulse = Pulse() internal internal(set) lazy var pulse: Pulse = Pulse()
/// PulseAnimation value. /// PulseAnimation value.
open var pulseAnimation: PulseAnimation { open var pulseAnimation: PulseAnimation {
...@@ -119,12 +119,14 @@ open class TableViewCell: UITableViewCell { ...@@ -119,12 +119,14 @@ open class TableViewCell: UITableViewCell {
*/ */
open func pulse(point: CGPoint? = nil) { open func pulse(point: CGPoint? = nil) {
let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point! let p = nil == point ? CGPoint(x: CGFloat(width / 2), y: CGFloat(height / 2)) : point!
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: p, width: width, height: height, pulse: &pulse)
var s = self
MotionPulseAnimation<TableViewCell>.pulseExpandAnimation(&s, point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(time: 0.35) { [weak self] in
guard let s = self else { guard var s = self else {
return return
} }
Motion.pulseContractAnimation(layer: s.layer, visualLayer: s.visualLayer, pulse: &s.pulse) MotionPulseAnimation<TableViewCell>.pulseContractAnimation(&s)
} }
} }
...@@ -136,7 +138,8 @@ open class TableViewCell: UITableViewCell { ...@@ -136,7 +138,8 @@ open class TableViewCell: UITableViewCell {
*/ */
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
Motion.pulseExpandAnimation(layer: layer, visualLayer: visualLayer, point: layer.convert(touches.first!.location(in: self), from: layer), width: width, height: height, pulse: &pulse) var s = self
MotionPulseAnimation<TableViewCell>.pulseExpandAnimation(&s, point: layer.convert(touches.first!.location(in: s), from: layer))
} }
/** /**
...@@ -147,7 +150,8 @@ open class TableViewCell: UITableViewCell { ...@@ -147,7 +150,8 @@ open class TableViewCell: UITableViewCell {
*/ */
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<TableViewCell>.pulseContractAnimation(&s)
} }
/** /**
...@@ -158,7 +162,8 @@ open class TableViewCell: UITableViewCell { ...@@ -158,7 +162,8 @@ open class TableViewCell: UITableViewCell {
*/ */
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
Motion.pulseContractAnimation(layer: layer, visualLayer: visualLayer, pulse: &pulse) var s = self
MotionPulseAnimation<TableViewCell>.pulseContractAnimation(&s)
} }
/** /**
......
...@@ -37,7 +37,7 @@ open class View: UIView { ...@@ -37,7 +37,7 @@ open class View: UIView {
allows the dropshadow effect on the backing layer, while clipping allows the dropshadow effect on the backing layer, while clipping
the image to a desired shape within the visualLayer. the image to a desired shape within the visualLayer.
*/ */
open fileprivate(set) lazy var visualLayer = CAShapeLayer() open internal(set) lazy var visualLayer = CAShapeLayer()
/** /**
A property that manages an image for the visualLayer's contents A property that manages an image for the visualLayer's contents
......
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