├── 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 | --------------------------------------------------------------------------------