├── 01_PlaygroundIntro.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 02_Vignettes.playground
├── Contents.swift
├── Resources
│ └── clownfish.png
├── contents.xcplayground
└── timeline.xctimeline
├── 03_EmojiGraphics.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 04_IconWiggle.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 05_ShapeLayer.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 06_ShapeLayerTwo.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 07_Zaxis.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 08_RotationMeasurements.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 09_Spinner.playground
├── Contents.swift
├── Resources
│ ├── clownfish.png
│ ├── phishlogo.png
│ ├── swift.png
│ └── swift_small.png
├── contents.xcplayground
└── timeline.xctimeline
├── 10_Particles.playground
├── Pages
│ ├── Untitled Page 2.xcplaygroundpage
│ │ └── Contents.swift
│ └── Untitled Page.xcplaygroundpage
│ │ ├── Contents.swift
│ │ └── timeline.xctimeline
└── contents.xcplayground
├── 11_ParticlesArray.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 12_LetterLogo.playground
├── Contents.swift
└── contents.xcplayground
├── 13_LetterLogo2.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── 14_LetterLogo3.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
├── BCAwSP.key
└── README.md
/01_PlaygroundIntro.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: # Better CoreAnimation with Swift Playgrounds
2 | //: ## Russell Mirabelli
3 | //: ## BottleRocket Studios
4 |
5 | import UIKit
6 | import PlaygroundSupport
7 |
8 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
9 | view.backgroundColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)
10 | PlaygroundPage.current.liveView = view
11 |
12 |
--------------------------------------------------------------------------------
/01_PlaygroundIntro.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/01_PlaygroundIntro.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/02_Vignettes.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | PlaygroundPage.current.liveView = view
8 |
9 | let clownfish = #imageLiteral(resourceName: "clownfish.png")
10 |
11 | let imageLayer = CALayer()
12 | imageLayer.frame = view.frame
13 | imageLayer.contents = clownfish.cgImage
14 | imageLayer.contentsGravity = kCAGravityCenter
15 |
16 | view.layer.addSublayer(imageLayer)
17 |
18 | let alpha:CGFloat = 0.9
19 | let colors = [
20 | UIColor.clear.cgColor,
21 | UIColor.lightGray.withAlphaComponent(alpha).cgColor,
22 | UIColor.darkGray.withAlphaComponent(alpha).cgColor,
23 | UIColor.black.withAlphaComponent(alpha).cgColor
24 | ]
25 |
26 | let gradient = CAGradientLayer()
27 | gradient.frame = view.frame
28 | gradient.colors = colors
29 | gradient.locations = [0.7,0.9,0.95]
30 |
31 | view.layer.addSublayer(gradient)
32 |
33 | let textLayer = CATextLayer()
34 | textLayer.frame = view.frame
35 | textLayer.frame.origin.y = 350
36 | textLayer.string = "Jenny Huang"
37 | textLayer.alignmentMode = kCAAlignmentRight
38 |
39 | view.layer.addSublayer(textLayer)
40 |
--------------------------------------------------------------------------------
/02_Vignettes.playground/Resources/clownfish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/02_Vignettes.playground/Resources/clownfish.png
--------------------------------------------------------------------------------
/02_Vignettes.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/02_Vignettes.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/03_EmojiGraphics.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = UIColor.blue
8 | PlaygroundPage.current.liveView = view
9 |
10 | let textLayer = CATextLayer()
11 | textLayer.frame = view.frame
12 | textLayer.string = "🎸"
13 | textLayer.fontSize = 300
14 | textLayer.alignmentMode = kCAAlignmentCenter
15 |
16 | view.layer.addSublayer(textLayer)
17 |
18 |
19 |
--------------------------------------------------------------------------------
/03_EmojiGraphics.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/03_EmojiGraphics.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/04_IconWiggle.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | let iconLayer = CATextLayer()
11 | iconLayer.alignmentMode = kCAAlignmentCenter
12 | iconLayer.frame = view.frame.insetBy(dx: 160, dy: 160)
13 | iconLayer.fontSize = 60
14 | iconLayer.string = "🎸"
15 | iconLayer.backgroundColor = UIColor.lightGray.cgColor
16 | iconLayer.cornerRadius = 15
17 | view.layer.addSublayer(iconLayer)
18 |
19 | let animation = CABasicAnimation(keyPath: "transform")
20 | animation.duration = 0.1
21 | animation.fromValue = NSValue(caTransform3D: CATransform3DIdentity)
22 | animation.fromValue = NSValue(caTransform3D:CATransform3DMakeRotation(
23 | -CGFloat.pi * 0.01, 0, 0, 1))
24 | animation.toValue = NSValue(caTransform3D:CATransform3DMakeRotation(
25 | CGFloat.pi * 0.01, 0, 0, 1))
26 | animation.autoreverses = true
27 | animation.repeatCount = HUGE
28 |
29 | iconLayer.add(animation, forKey: nil)
30 |
31 |
--------------------------------------------------------------------------------
/04_IconWiggle.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/04_IconWiggle.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/05_ShapeLayer.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | let shapeLayer = CAShapeLayer()
11 | shapeLayer.frame = view.frame
12 | view.layer.addSublayer(shapeLayer)
13 |
14 | let path = CGPath(ellipseIn: shapeLayer.frame.insetBy(dx: 30, dy: 30), transform: nil)
15 | shapeLayer.path = path
16 | shapeLayer.fillColor = UIColor.white.cgColor
17 |
18 | let animation = CABasicAnimation(keyPath: "opacity")
19 | animation.duration = 2.0
20 | animation.repeatCount = Float.infinity
21 | animation.fromValue = 1.0
22 | animation.toValue = 0.3
23 | animation.autoreverses = true
24 | animation.repeatCount = Float.infinity
25 | shapeLayer.add(animation, forKey: "opacity")
26 |
27 | let path2 = CGPath(ellipseIn: shapeLayer.frame.insetBy(dx: 10, dy: 70), transform: nil)
28 |
29 | let animation2 = CABasicAnimation(keyPath: "path")
30 | animation2.duration = 1.5
31 | animation2.repeatCount = Float.infinity
32 | animation2.fromValue = path
33 | animation2.toValue = path2
34 | animation2.autoreverses = true
35 | animation2.repeatCount = Float.infinity
36 | shapeLayer.add(animation2, forKey: nil)
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/05_ShapeLayer.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/05_ShapeLayer.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/06_ShapeLayerTwo.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | func path(from: String) -> UIBezierPath? {
11 | var unichars = [UniChar](from.utf16)
12 | var glyphs = [CGGlyph](repeating: 0, count: unichars.count)
13 | let font = UIFont(name: "Menlo", size: 100)!
14 | let success = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)
15 | if success {
16 | return UIBezierPath(cgPath: CTFontCreatePathForGlyph(font, glyphs.first!, nil)!)
17 | }
18 |
19 | return nil
20 | }
21 |
22 | //class AnimationDelegate : NSObject {
23 | //
24 | //}
25 | //
26 | //extension AnimationDelegate: CAAnimationDelegate {
27 | // func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
28 | // print("done")
29 | // }
30 | //}
31 | //
32 | //let delegate = AnimationDelegate()
33 |
34 | let layer = CAShapeLayer()
35 | layer.frame = view.layer.frame.insetBy(dx: 50, dy: 50)
36 | view.layer.addSublayer(layer)
37 |
38 | let bPath = path(from: "B")?.cgPath
39 |
40 | layer.path = bPath
41 | layer.isGeometryFlipped = true
42 |
43 | let rPath = path(from: "R")?.cgPath
44 | let animation = CABasicAnimation(keyPath: "path")
45 | animation.duration = 3.0
46 | animation.fromValue = bPath
47 | animation.toValue = rPath
48 | animation.isRemovedOnCompletion = false
49 | layer.add(animation, forKey: nil)
50 | layer.path = rPath // set this immediately after adding animation to make it "stick"
51 |
52 |
53 | //animation.delegate = delegate
54 |
--------------------------------------------------------------------------------
/06_ShapeLayerTwo.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/06_ShapeLayerTwo.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/07_Zaxis.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 |
11 |
12 | let layer = CATextLayer()
13 | layer.backgroundColor = UIColor.white.cgColor
14 | layer.cornerRadius = 10
15 | layer.frame = view.frame.insetBy(dx: 100, dy: 100)
16 | layer.string = "🐰"
17 | layer.fontSize = 148
18 | layer.alignmentMode = kCAAlignmentCenter
19 | layer.foregroundColor = UIColor.red.cgColor
20 |
21 | view.layer.addSublayer(layer)
22 |
23 |
24 | let animation = CABasicAnimation(keyPath: "transform")
25 | animation.duration = 5.0
26 | animation.fromValue = NSValue(caTransform3D: CATransform3DMakeRotation(-CGFloat.pi, 0, 1, 0))
27 | animation.toValue = NSValue(caTransform3D: CATransform3DMakeRotation(0.0, 0, 1, 0))
28 | animation.repeatCount = Float.infinity
29 | layer.add(animation, forKey: nil)
30 |
31 | var transform = CATransform3DIdentity
32 | transform.m34 = -1.0/500.0
33 | view.layer.sublayerTransform = transform
34 |
--------------------------------------------------------------------------------
/07_Zaxis.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/07_Zaxis.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/08_RotationMeasurements.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.9411764741, green: 0.4980392158, blue: 0.3529411852, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | let textLayer = CATextLayer()
11 | textLayer.string = "🐠"
12 | textLayer.fontSize = 100
13 | textLayer.frame = view.frame
14 | textLayer.alignmentMode = kCAAlignmentCenter
15 | view.layer.addSublayer(textLayer)
16 |
17 | let rotationInDegrees = Measurement(value: 45, unit: UnitAngle.degrees)
18 | let rotationInRadians = CGFloat(rotationInDegrees.converted(to: .radians).value)
19 | let transform = CATransform3DMakeRotation(rotationInRadians, 0, 0.0, 1.0)
20 | textLayer.transform = transform
21 |
22 | let animation = CABasicAnimation(keyPath: "transform")
23 | animation.fromValue = NSValue(caTransform3D: CATransform3DMakeRotation(CGFloat(Measurement(value: 10, unit: UnitAngle.degrees).converted(to: .radians).value), 0, 0.0, 1.0))
24 | animation.toValue = NSValue(caTransform3D: CATransform3DMakeRotation(CGFloat(Measurement(value: -10, unit: UnitAngle.degrees).converted(to: .radians).value), 0, 0.0, 1.0))
25 | animation.duration = 2.0
26 | animation.repeatCount = Float.infinity
27 | animation.autoreverses = true
28 | textLayer.add(animation, forKey: nil)
29 |
30 | ////let timingFunction = CAMediaTimingFunction(controlPoints: 0.08, 0.04, 0.08, 0.99)
31 | ////
32 | ////animation.timingFunction = timingFunction
33 |
34 |
35 | let position = CABasicAnimation(keyPath: "position.x")
36 | position.fromValue = view.frame.width
37 | position.toValue = 0
38 | position.duration = 10.0
39 | position.repeatCount = Float.infinity
40 |
41 | textLayer.add(position, forKey: nil)
42 |
--------------------------------------------------------------------------------
/08_RotationMeasurements.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/08_RotationMeasurements.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/09_Spinner.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 600, height: 600))
7 | view.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | let guitarLayer = CATextLayer()
11 | guitarLayer.string = "🎸"
12 | guitarLayer.fontSize = 35
13 | guitarLayer.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
14 | guitarLayer.position = CGPoint(x: 75, y: 75)
15 | guitarLayer.cornerRadius = 25
16 |
17 | let fadeGuitar = CABasicAnimation(keyPath: "opacity")
18 | fadeGuitar.fromValue = 1.0
19 | fadeGuitar.toValue = 0.0
20 | fadeGuitar.repeatCount = HUGE
21 | fadeGuitar.duration = 1.0
22 | guitarLayer.add(fadeGuitar, forKey: "opacity")
23 |
24 | let replication = CAReplicatorLayer()
25 | replication.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
26 | replication.position = view.center
27 | replication.instanceCount = 10
28 | replication.instanceDelay = 0.1
29 | replication.instanceTransform = CATransform3DMakeRotation(CGFloat(M_PI/5), 0, 0, 1)
30 | replication.addSublayer(guitarLayer)
31 | view.layer.addSublayer(replication)
32 |
--------------------------------------------------------------------------------
/09_Spinner.playground/Resources/clownfish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/09_Spinner.playground/Resources/clownfish.png
--------------------------------------------------------------------------------
/09_Spinner.playground/Resources/phishlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/09_Spinner.playground/Resources/phishlogo.png
--------------------------------------------------------------------------------
/09_Spinner.playground/Resources/swift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/09_Spinner.playground/Resources/swift.png
--------------------------------------------------------------------------------
/09_Spinner.playground/Resources/swift_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/09_Spinner.playground/Resources/swift_small.png
--------------------------------------------------------------------------------
/09_Spinner.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/09_Spinner.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/10_Particles.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | //: [Previous](@previous)
2 |
3 | import Foundation
4 |
5 | var str = "Hello, playground"
6 |
7 | //: [Next](@next)
8 |
--------------------------------------------------------------------------------
/10_Particles.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | let icon = CATextLayer()
11 | icon.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
12 | icon.fontSize = 30
13 | icon.string = "❤️"
14 |
15 | // new for iOS 10
16 | let renderer = UIGraphicsImageRenderer.init(bounds: icon.frame)
17 | let image = renderer.image { (context) in
18 | icon.render(in: context.cgContext)
19 | }
20 |
21 | let emitter = CAEmitterLayer()
22 | emitter.frame = view.frame
23 | view.layer.addSublayer(emitter)
24 |
25 | let cell = CAEmitterCell()
26 | cell.contents = image.cgImage
27 | cell.birthRate = 2
28 | cell.speed = 10.0
29 | cell.lifetime = 10
30 |
31 | emitter.emitterCells = [cell]
32 | emitter.emitterPosition = CGPoint(x: 200, y: 200)
33 | emitter.emitterShape = kCAEmitterLayerSphere
34 | emitter.emitterSize = CGSize(width: 400, height: 400)
35 | emitter.renderMode = kCAEmitterLayerOldestFirst
36 |
37 | cell.velocity = 3.0
38 | cell.yAcceleration = 3.3
39 | cell.xAcceleration = 3.3
40 | cell.scale = 1.0
41 | cell.scaleRange = 1.0
42 | cell.scaleSpeed = 0.5
43 | cell.lifetimeRange = 10
44 | cell.spin = 1.0
45 | cell.spinRange = 10.0
46 | cell.alphaSpeed = -0.1
47 |
--------------------------------------------------------------------------------
/10_Particles.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/10_Particles.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/11_ParticlesArray.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 |
6 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
7 | view.backgroundColor = #colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1)
8 | PlaygroundPage.current.liveView = view
9 |
10 | func createCell(string: String) -> CAEmitterCell {
11 | let icon = CATextLayer()
12 | icon.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
13 | icon.fontSize = 30
14 | icon.string = string
15 |
16 | // new for iOS 10
17 | let renderer = UIGraphicsImageRenderer.init(bounds: icon.frame)
18 | let image = renderer.image { (context) in
19 | icon.render(in: context.cgContext)
20 | }
21 | let cell = CAEmitterCell()
22 | cell.contents = image.cgImage
23 | cell.birthRate = 0.5
24 | cell.speed = 10.0
25 | cell.lifetime = 15
26 |
27 | cell.velocity = 3.0
28 | cell.yAcceleration = 3.3
29 | cell.xAcceleration = 3.3
30 | cell.scale = 1.0
31 | cell.scaleRange = 1.0
32 | cell.scaleSpeed = 0.5
33 | cell.lifetimeRange = 10
34 | cell.spin = 1.0
35 | cell.spinRange = 10.0
36 | cell.alphaSpeed = -0.9
37 |
38 | return cell
39 | }
40 |
41 | func createCellArray(string: String) -> [CAEmitterCell] {
42 | return string.characters.map() { createCell(string: String($0)) }
43 | }
44 |
45 | let emitter = CAEmitterLayer()
46 | emitter.frame = view.frame
47 | view.layer.addSublayer(emitter)
48 |
49 | //emitter.emitterCells = [createCell(string: "❤️"),createCell(string: "💛"),createCell(string: "💚"),createCell(string: "💙"),createCell(string: "💜")]
50 |
51 | emitter.emitterCells = createCellArray(string: "❤️💛💚💙💜💕💞💗")
52 |
53 | emitter.emitterPosition = CGPoint(x: 200, y: 200)
54 | emitter.emitterShape = kCAEmitterLayerSphere
55 | emitter.emitterSize = CGSize(width: 400, height: 400)
56 | emitter.renderMode = kCAEmitterLayerOldestFirst
57 |
58 |
--------------------------------------------------------------------------------
/11_ParticlesArray.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/11_ParticlesArray.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/12_LetterLogo.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 | import GameKit
6 |
7 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 256, height: 256))
8 | view.backgroundColor = .black
9 | PlaygroundPage.current.liveView = view
10 |
11 | func getSingleCharacterLayer(c: Character, font: UIFont) -> CATextLayer {
12 | let layer = CATextLayer()
13 | layer.frame = CGRect(x: 0, y: 0, width: 10, height: 20)
14 | layer.font = font
15 | layer.fontSize = 12 // does not use font's size...
16 | layer.string = String(c)
17 | return layer
18 | }
19 |
20 | let random = GKMersenneTwisterRandomSource()
21 | let colors: [UIColor] = [
22 | #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1),#colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1),#colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1),#colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1),#colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1),#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1),#colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1),#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),#colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1)
23 | ]
24 |
25 | func getRandomCharacterLayer(s: String, font: UIFont) -> CATextLayer {
26 | let randomIndex = random.nextInt(upperBound: s.characters.count)
27 | let character = s.characters[s.index(s.startIndex, offsetBy: randomIndex)]
28 | let layer = getSingleCharacterLayer(c: character, font: font)
29 | layer.foregroundColor = colors[random.nextInt(upperBound: colors.count)].cgColor
30 | return layer
31 | }
32 |
33 | let characterSet = "!@#$%^&*()-=+{}[]|\\;:<>?/~`\""
34 |
35 | var height:CGFloat = 0
36 | let font = UIFont(name: "Menlo", size: 32)
37 | repeat {
38 | var width: CGFloat = 0
39 | repeat {
40 | let charLayer = getRandomCharacterLayer(s: characterSet, font: font!)
41 | charLayer.frame = CGRect(x: width, y: height, width: 8, height: 12)
42 | view.layer.addSublayer(charLayer)
43 |
44 | width += 10.0
45 | } while (width < view.frame.width)
46 | height += 18.0
47 | } while (height < view.frame.height)
48 |
49 | let imageRenderer = UIGraphicsImageRenderer(bounds: view.frame)
50 | let jpeg = imageRenderer.jpegData(withCompressionQuality: 1.0) { (context) in
51 | view.layer.render(in: context.cgContext)
52 | }
53 |
54 | // must create '~/Documents/Shared Playground Data' manually
55 | let URL = playgroundSharedDataDirectory.appendingPathComponent("file.jpeg")
56 | print(URL)
57 |
58 | try! jpeg.write(to: URL)
59 | print("done")
60 |
--------------------------------------------------------------------------------
/12_LetterLogo.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/13_LetterLogo2.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 | import GameKit
6 |
7 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 256, height: 256))
8 | view.backgroundColor = .black
9 | PlaygroundPage.current.liveView = view
10 |
11 | func getSingleCharacterLayer(c: Character, font: UIFont) -> CATextLayer {
12 | let layer = CATextLayer()
13 | layer.frame = CGRect(x: 0, y: 0, width: 10, height: 20)
14 | layer.font = font
15 | layer.fontSize = 12 // does not use font's size...
16 | layer.string = String(c)
17 | return layer
18 | }
19 |
20 | let random = GKMersenneTwisterRandomSource()
21 | let colors: [UIColor] = [
22 | #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1),#colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1),#colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1),#colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1),#colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1),#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1),#colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1),#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),#colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1)
23 | ]
24 |
25 | func getRandomCharacterLayer(s: String, font: UIFont) -> CATextLayer {
26 | let randomIndex = random.nextInt(upperBound: s.characters.count)
27 | let character = s.characters[s.index(s.startIndex, offsetBy: randomIndex)]
28 | let layer = getSingleCharacterLayer(c: character, font: font)
29 | layer.foregroundColor = colors[random.nextInt(upperBound: colors.count)].cgColor
30 | return layer
31 | }
32 |
33 | let characterSet = "!@#$%^&*()-=+{}[]|\\;:<>?/~`\""
34 |
35 | var height:CGFloat = 0
36 | let font = UIFont(name: "Menlo", size: 32)
37 | repeat {
38 | var width: CGFloat = 0
39 | repeat {
40 | let charLayer = getRandomCharacterLayer(s: characterSet, font: font!)
41 | charLayer.frame = CGRect(x: width, y: height, width: 8, height: 12)
42 | view.layer.addSublayer(charLayer)
43 |
44 | width += 10.0
45 | } while (width < view.frame.width)
46 | height += 18.0
47 | } while (height < view.frame.height)
48 |
49 | let maskLayer = CALayer()
50 | maskLayer.frame = view.frame
51 | maskLayer.backgroundColor = UIColor.clear.cgColor
52 |
53 | let letterLayer = CATextLayer()
54 | letterLayer.frame = maskLayer.frame
55 | letterLayer.fontSize = 200
56 |
57 | letterLayer.alignmentMode = kCAAlignmentCenter
58 | letterLayer.string = "❤️"
59 | maskLayer.addSublayer(letterLayer)
60 |
61 | view.layer.mask = maskLayer
62 |
63 |
64 |
65 |
66 | let imageRenderer = UIGraphicsImageRenderer(bounds: view.frame)
67 | let jpeg = imageRenderer.jpegData(withCompressionQuality: 1.0) { (context) in
68 | view.layer.render(in: context.cgContext)
69 | }
70 | // must create '~/Documents/Shared Playground Data' manually
71 | let URL = playgroundSharedDataDirectory.appendingPathComponent("file.jpeg")
72 | print(URL)
73 |
74 | try! jpeg.write(to: URL)
75 | print("done")
76 |
--------------------------------------------------------------------------------
/13_LetterLogo2.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/13_LetterLogo2.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/14_LetterLogo3.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import PlaygroundSupport
5 | import GameKit
6 |
7 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 348, height: 348))
8 | view.backgroundColor = .black
9 | PlaygroundPage.current.liveView = view
10 |
11 | func getSingleCharacterLayer(c: Character, font: UIFont) -> CATextLayer {
12 | let layer = CATextLayer()
13 | layer.frame = CGRect(x: 0, y: 0, width: 10, height: 20)
14 | layer.font = font
15 | layer.fontSize = 12 // does not use font's size...
16 | layer.string = String(c)
17 | return layer
18 | }
19 |
20 | let random = GKMersenneTwisterRandomSource()
21 | let colors: [UIColor] = [
22 | #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1),#colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1),#colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1),#colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1),#colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1),#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1),#colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1),#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),#colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1)
23 | ]
24 |
25 | func getRandomCharacterLayer(s: String, font: UIFont) -> CATextLayer {
26 | let randomIndex = random.nextInt(upperBound: s.characters.count)
27 | let character = s.characters[s.index(s.startIndex, offsetBy: randomIndex)]
28 | let layer = getSingleCharacterLayer(c: character, font: font)
29 | layer.foregroundColor = colors[random.nextInt(upperBound: colors.count)].cgColor
30 | return layer
31 | }
32 |
33 | let characterSet = "!@#$%^&*()-=+{}[]|\\;:<>?/~`\""
34 |
35 | var height:CGFloat = 0
36 | let font = UIFont(name: "Menlo", size: 32)
37 | var sublayers:[CATextLayer] = []
38 | repeat {
39 | var width: CGFloat = 0
40 | repeat {
41 | let charLayer = getRandomCharacterLayer(s: characterSet, font: font!)
42 | charLayer.frame = CGRect(x: width, y: height, width: 8, height: 12)
43 | view.layer.addSublayer(charLayer)
44 | sublayers.append(charLayer)
45 | width += 10.0
46 | } while (width < view.frame.width)
47 | height += 18.0
48 | } while (height < view.frame.height)
49 |
50 | let maskLayer = CALayer()
51 | maskLayer.frame = view.frame
52 | maskLayer.backgroundColor = UIColor.clear.cgColor
53 |
54 | let letterLayer = CATextLayer()
55 | letterLayer.frame = maskLayer.frame
56 | letterLayer.fontSize = 260
57 |
58 | letterLayer.alignmentMode = kCAAlignmentCenter
59 | letterLayer.string = "❤️"
60 | maskLayer.addSublayer(letterLayer)
61 |
62 | view.layer.mask = maskLayer
63 |
64 | class Updater {
65 | let layer: CALayer
66 | let characters: String
67 | let font: UIFont
68 | init(l: CALayer, c: String, f: UIFont) {
69 | layer = l
70 | characters = c
71 | font = f
72 | }
73 | @objc func update() {
74 | let randomIndex = random.nextInt(upperBound: layer.sublayers!.count)
75 | let sub = layer.sublayers![randomIndex]
76 | let newSub = getRandomCharacterLayer(s: characters, font: font)
77 | newSub.frame = sub.frame
78 | sub.removeFromSuperlayer()
79 | layer.addSublayer(newSub)
80 | }
81 | }
82 |
83 | let updater = Updater(l: view.layer, c: characterSet, f: font!)
84 | let displayLink = CADisplayLink(target: updater, selector: #selector(Updater.update))
85 | displayLink.add(to: RunLoop.current, forMode: .defaultRunLoopMode)
86 |
--------------------------------------------------------------------------------
/14_LetterLogo3.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/14_LetterLogo3.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/BCAwSP.key:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmirabelli/CoreAnimationSwiftPlaygrounds/9fa10eb5ff1160c862a1b280ce39670816175b7f/BCAwSP.key
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CoreAnimationSwiftPlaygrounds
2 | Slide deck and playgrounds from this presentation from 360iDev 2016
3 |
4 | It's become very easy to simply rely on UIView animations, but there's some great things that you can accomplish by using
5 | its underlying foundation, CoreAnimation.
6 |
7 | In this presentation, and through these playgrounds, I demonstrate how to take advantage of the fast iteration available
8 | in Swift Playgrounds to develop effects that are worthwhile can can elevate you app. Free yourself of the tyranny of the
9 | edit-compile-run cycle, and get some cool (and fun) things happening!
10 |
11 | Be sure to open the Assistant View (locked rings) to see the samples in operation.
12 |
13 | A video of the full presentation is available at https://www.youtube.com/watch?v=bw11HjQyrtE
14 |
--------------------------------------------------------------------------------