SlideShare a Scribd company logo
1 of 57
Download to read offline
Advanced Graphics with Core
Animation
ティム•オリバー
• Core Animationのアニメーションの実装方
法
• Core Animationを少し紹介する
• CALayer のスブクラスの利用方法
Overview
@TimOliverAU
• 2015年3月Realmに入った
• オーストラリアのパースの出
身
• iOS開発をやってるのは約6年
間
• カラオケが大好き!
try! Swift - Advanced Graphics with Core Animation
My Relation with Japan
• 帰国してから日本語の勉強を始め
た
• 1996年に千葉県の小学校入学
• 2007年、新潟県のスキー場で
ワーホリ
• 2013年、pixivでiOS開発
try! Swift - Advanced Graphics with Core Animation
iComics
• とんでもない画像データ
• DRMフリー•コミック•リーダ
ー
• Core Animationを結構利
用している
• (おまけに、Realmも! ^_^)
What’s Core Animation?
© Apple Inc.
• UIKitから下のレベル
What’s Core Animation?
• オペレーションをGPUに
転送させている
• UIViewと深くつながって
る
• iOSのグラフィクもアニ
メーションも管理する
• レイヤ•オブジェクトの階層
• ビットマップのようなコン
テンツがセットできる
• このようにゲームの開発と
同じのようになる!
Why is it good to know?
• iOSのグラフィックス•システムをもっと理解でき
る
• 60FPSをもっと簡単に目指す事ができる!
• UIViewのAPIより、もっときれい、もっと複
雑なアニーションが可能性になる
• というわけで、アプリが他にも目立つ!
What about Core Graphics?
override func drawRect(_ rect: CGRect) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()
//// Color Declarations
let fillColor = UIColor(red: 0.808, green: 0.000, blue: 0.000, alpha: 1.000)
//// Oval Drawing
let ovalPath = UIBezierPath(ovalInRect: CGRectMake(9, 8, 494, 494))
fillColor.setFill()
ovalPath.fill()
//// Bezier Drawing
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointMake(334.34, 360.7))
bezierPath.addCurveToPoint(CGPointMake(196.21, 362.32), controlPoint1: CGPointMake(297.59, 381.88), controlPoint2: CGPointMake(247.05, 384.06))
bezierPath.addCurveToPoint(CGPointMake(99, 279.29), controlPoint1: CGPointMake(155.05, 344.84), controlPoint2: CGPointMake(120.9, 314.25))
bezierPath.addCurveToPoint(CGPointMake(134.91, 301.14), controlPoint1: CGPointMake(109.51, 288.03), controlPoint2: CGPointMake(121.77, 295.02))
bezierPath.addCurveToPoint(CGPointMake(276.84, 301.2), controlPoint1: CGPointMake(187.41, 325.7), controlPoint2: CGPointMake(239.9, 324.01))
bezierPath.addCurveToPoint(CGPointMake(276.79, 301.14), controlPoint1: CGPointMake(276.82, 301.18), controlPoint2: CGPointMake(276.8, 301.16))
bezierPath.addCurveToPoint(CGPointMake(146.29, 165.67), controlPoint1: CGPointMake(224.24, 260.93), controlPoint2: CGPointMake(179.57, 208.49))
bezierPath.addCurveToPoint(CGPointMake(128.78, 142.08), controlPoint1: CGPointMake(139.29, 158.68), controlPoint2: CGPointMake(134.03, 149.94))
bezierPath.addCurveToPoint(CGPointMake(255.76, 238.22), controlPoint1: CGPointMake(169.06, 178.78), controlPoint2: CGPointMake(233, 225.1))
bezierPath.addCurveToPoint(CGPointMake(166.43, 126.34), controlPoint1: CGPointMake(207.6, 187.52), controlPoint2: CGPointMake(164.68, 124.6))
bezierPath.addCurveToPoint(CGPointMake(313.57, 246.95), controlPoint1: CGPointMake(242.63, 203.25), controlPoint2: CGPointMake(313.57, 246.95))
bezierPath.addCurveToPoint(CGPointMake(319.19, 250.36), controlPoint1: CGPointMake(315.92, 248.27), controlPoint2: CGPointMake(317.73, 249.37))
bezierPath.addCurveToPoint(CGPointMake(323.2, 238.22), controlPoint1: CGPointMake(320.72, 246.46), controlPoint2: CGPointMake(322.07, 242.41))
bezierPath.addCurveToPoint(CGPointMake(290.8, 101), controlPoint1: CGPointMake(335.47, 193.64), controlPoint2: CGPointMake(321.46, 142.95))
bezierPath.addCurveToPoint(CGPointMake(386.26, 291.53), controlPoint1: CGPointMake(361.74, 143.82), controlPoint2: CGPointMake(403.78, 224.23))
bezierPath.addCurveToPoint(CGPointMake(384.77, 296.89), controlPoint1: CGPointMake(385.8, 293.34), controlPoint2: CGPointMake(385.3, 295.13))
bezierPath.addCurveToPoint(CGPointMake(385.38, 297.65), controlPoint1: CGPointMake(384.97, 297.14), controlPoint2: CGPointMake(385.18, 297.39))
bezierPath.addCurveToPoint(CGPointMake(406.4, 378.93), controlPoint1: CGPointMake(420.41, 341.35), controlPoint2: CGPointMake(410.78, 387.67))
bezierPath.addCurveToPoint(CGPointMake(334.34, 360.7), controlPoint1: CGPointMake(387.4, 341.82), controlPoint2: CGPointMake(352.22, 353.17))
bezierPath.closePath()
bezierPath.miterLimit = 4;
UIColor.whiteColor().setFill()
bezierPath.fill()
//// Text Drawing
let textRect = CGRectMake(35, 144, 50, 140)
let textTextContent = NSString(string: "{")
let textStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
textStyle.alignment = .Left
let textFontAttributes = [NSFontAttributeName: UIFont.systemFontOfSize(107), NSForegroundColorAttributeName: UIColor.whiteColor(), NSParagraphStyleAttributeName: textStyle]
let textTextHeight: CGFloat = textTextContent.boundingRectWithSize(CGSizeMake(textRect.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: textFontAttributes, context: nil).size.height
CGContextSaveGState(context)
CGContextClipToRect(context, textRect);
textTextContent.drawInRect(CGRectMake(textRect.minX, textRect.minY + (textRect.height - textTextHeight) / 2, textRect.width, textTextHeight), withAttributes: textFontAttributes)
CGContextRestoreGState(context)
//// Text 2 Drawing
let text2Rect = CGRectMake(440, 143, 50, 140)
let text2TextContent = NSString(string: "}")
let text2Style = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
text2Style.alignment = .Left
let text2FontAttributes = [NSFontAttributeName: UIFont.systemFontOfSize(107), NSForegroundColorAttributeName: UIColor.whiteColor(), NSParagraphStyleAttributeName: text2Style]
let text2TextHeight: CGFloat = text2TextContent.boundingRectWithSize(CGSizeMake(text2Rect.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: text2FontAttributes, context: nil).size.height
CGContextSaveGState(context)
CGContextClipToRect(context, text2Rect);
text2TextContent.drawInRect(CGRectMake(text2Rect.minX, text2Rect.minY + (text2Rect.height - text2TextHeight) / 2, text2Rect.width, text2TextHeight), withAttributes: text2FontAttributes)
CGContextRestoreGState(context)
}
• 完全にCPUで実行
•Core Animationと合わせ
たらかなりにいい!
•前の世代のデバイスで非
常に遅い可能性
•画像作成するAPI
Core Graphics
PaintCode on the Mac App
So. Core Animation?
import QuartzCore
let newLayer = CALayer()
newLayer.frame = CGRectMake(0, 0, 100, 100)
newLayer.backgroundColor = UIColor.redColor().CGColor
• レイヤ•オブジェクトの階層で実装
• 基本的なクラスは CALayer
So. Core Animation?
import QuartzCore
let newLayer = CALayer()
newLayer.frame = CGRectMake(0, 0, 100, 100)
newLayer.backgroundColor = UIColor.redColor().CGColor
newLayer.cornerRadius = 10
• レイヤ•オブジェクトの階層で実装
• 基本的なクラスは CALayer
CALayer
Where is it in UIKit?
UIViewUIView
CALayer
Where is it in UIKit?
public class UIView {
public var layer: CALayer { get }
}
UIView
Deeply integrated with UIView
public class UIView {
public var frame: CGRect {
get {
return self.layer.frame
}
set {
self.layer.frame = newValue
}
}
}
let newLayer = CALayer()
view.layer.addSublayer(newLayer)
• CALayerプロパティーが
UIViewで示されてる
• ‘frame’ は CALayerの
‘position’ と‘bounds’ プロパ
ティーで計っている.
Why is it not a superclass?
• UIViewのlayerのクラスが変わる事もある。
• 普通のサブクラスの実装で不可能
public class MyGradientClass : UIView {
override class func layerClass() -> AnyClass {
return CAGradientLayer.self
}
}
Mapping contents to CALayer
let trySwiftLogo = self.trySwiftLogo() as UIImage
let trySwiftLayer = CALayer()
trySwiftLayer.contents = trySwiftLogo.CGImage
(アニメーションも可!)
Managing the scale of CALayer
contentstrySwiftLayer.contentsGravity
kCAGravityResize
kCAGravityResizeAspectFill
kCAGravityResizeAspect
kCAGravityCenter
Tweetbot
UIImage
UIImageVie
w
CALayer
kCAGravityLeft
CALayer
kCAGravityRight
Bitmap sampling in CALayer
trySwiftLayer.minificationFilter trySwiftLayer.magnificationFilter
kCAFilterTrilinear
Best Quality
(Slowest)
kCAFilterLinear
Default
kCAFilterNearest
Lowest Quality (Fast)
Bitmap sampling in CALayer
Masking CALayer Objects
let myLayer = CALayer()
myLayer.contents = self.makeRedCircleImage().CGImage
let myMask = CALayer()
myMask.contents = self.makeMaskImage().CGImage
myLayer.mask = myMask
+ =
myLayer myMask
Device Layer
Pages Layer
Arrow Layer
Mask Layer
Adding Shadows to CALayer
let myLayer = view.layer
myLayer.shadowColor = UIColor.blackColor().CGColor
myLayer.shadowOpacity = 0.75
myLayer.shadowOffset = CGSizeMake(5, 10)
myLayer.shadowRadius = 10
// IMPORTANT FOR PERFORMANCE
let myShadowPath = UIBezierPath(roundedRect:
view.bounds, cornerRadius: 10)
myLayer.shadowPath = myShadowPath.CGPath
Transforming a CALayer
let myLayer = CALayer()
myLayer.contents = self.makeTrySwiftLogoImage().CGImage
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -500
transform = CATransform3DRotate(transform, 45.0f * M_PI / 180.0, 0, 1, 0)
myLayer.transform = transform
try! Swift - Advanced Graphics with Core Animation
Flipboard
Blend Modes with CALayer
let myBlendLayer = CALayer()
myBlendLayer.setValue(false, forKey: “allowsGroupBlending”) // PRIVATE
myBlendLayer.compositingFilter = “screenBlendMode"
myBlendLayer.allowsGroupOpacity = false
myLayer.addSublayer(myBlendLayer)
• 注意:Private APIを利用している!
+ =
CALayer - “destIn” Blend Mode
CALayer - “screenBlendMode” Blend
ModeCALayer - “linearLightBlendMode” Blend
ModeCAGradientLayer - “colorDodgeBlendMode” Blend
Mode
CALayer - “multiplyBlendMode” Blend Mode
CAShapeLayer - Normal Blend Mode
Reveal - http://revealapp.com
Animating with Core Animation
Compared to UIKit
let trySwiftView = UIImageView(image:)
let trySwiftView.center = CGPointZero
UIView.animateWithDuration(2, delay: 0, options: .CurveEaseInOut, animations: {
trySwiftView.center = CGPointMake(0, 500)
}, completion: nil)
CABasicAnimation
let trySwiftLayer = //…
let myAnimation = CABasicAnimation(keyPath: “position.x”)
myAnimation.duration = 2
myAnimation.fromValue = trySwiftLayer.position.x
myAnimation.toValue = trySwiftLayer.position.x + 500
myAnimation.timingFunction = kCAMediaTimingFunctionEaseInEaseOut
myAnimation.repeatCount = .infinity
trySwiftLayer.addAnimation(myAnimation, forKey: “myAnimationKeyName”)
CABasicAnimation
let trySwiftLayer = //…
let myAnimation = CABasicAnimation(keyPath: “position.x”)
myAnimation.duration = 2
myAnimation.fromValue = trySwiftLayer.position.x
myAnimation.toValue = trySwiftLayer.position.x + 500
myAnimation.timingFunction = kCAMediaTimingFunctionEaseInEaseOut
myAnimation.repeatCount = .infinity
trySwiftLayer.addAnimation(myAnimation, forKey: “myAnimationKeyName”)
Timing Function
let timingFunction = CAMediaTimingFunction(controlPoints: .08, .04, .08, .99)
let myAnimation = CABasicAnimation()
myAnimation.timingFunction = timingFunction
http://cubic-bezier.com
Animating a CALayer’s Contents
let imageView = UIImageView()
let onImage = UIImage()
let offImage = UIImage()
let myAnim = CABasicAnimation(keyPath: “contents”)
myAnim.fromValue = offImage.CGImage
myAnim.toValue = onImage.CGImage
myAnim.duration = 0.15
imageView.layer.addAnimation(myCrossfadeAnimation,
forKey: “contents”)
imageView.image = onImage
CAKeyframeAnimation
let rect = CGRectMake(0, 0, 200, 200)
let circlePath = UIBezierPath(ovalInRect:rect)
let circleAnimation = CAKeyframeAnimation()
circleAnimation.keyPath = “position”
circleAnimation.path = circlePath.CGPath
circleAnimation.duration = 4
// Manually specify keyframe points
// circleAnimation.values = //…
// circleAnimation.keyTimes = //..
let trySwiftLayer = //…
trySwiftLayer.addAnimation(circleAnimation,
forKey: “position”)
CAAnimationGroup
let myPositionAnimation = CABasicAnimation.animation(keyPath: “position”)
let myAlphaAnimation = CABasicAnimation.animation(keyPath: “opacity”)
let animationGroup = CAAnimationGroup()
animationGroup.timingFunction = kCAMediaTimingFunctionEaseInEaseOut
animationGroup.duration = 2
animationGroup.animations = [myPositionAnimation, myAlphaAnimation]
let trySwiftLayer = CALayer()
trySwiftLayer.addAnimation(animationGroup, forKey: “myAnimations”)
Animation Completion Handling
// Set a delegate object
let myAnimation = CABasicAnimation()
myAnimation.delegate = self
// Animation completion sent to ‘animationDidStop(anim: finished flag:)
// ———
//Set a closure to be executed at the end of this transaction
CATransaction.begin()
CATransaction.setCompletionBlock({
// Logic to be performed, post animation
})
CATransaction.commit()
CoreAnimator on the Mac App
Features of Core Animation
Subclasses
Features of Core Animation
Subclasses
• UIViewのサブクラスで入れる
• GPUで実行、特別なイフェクト
• 時々、CPUのオペレーションもある
public class MyGradientClass : UIView {
override class func layerClass() -> AnyClass {
return CAGradientLayer.self
}
}
CATileLayer
• 色々なサイズで画像を再レン
ダー
• PDFやSVGやベクトルデータ
なら非常に役に立つ!
• Core Graphicsでバックグラウ
ンドで実行
CAGradientLayer
• GPUでグラジエントをレンダ
ーする
•3Dに変換されたレイヤで簡単に
影のエフェクト
CAReplicaterLayer
© iNVASIVECODE 2015
https://vimeo.com/128046096
• GPUで一つのレイヤを
何回もコピーして表示
する
• サムネールやゲームで
も役に立つ
CAShapeLayer
UAProgressView
© Urban Apps 2014
• CGPathから色々な形が表示
させ、アニメーションさせる
• 読み込むアイコンにとても合って
る
•iOS 7のデザインスタイルにも似合って
る
CAEmitterLayer
Particle Playground on the Mac App Store
• レイヤの’frame’
からパーティク
ルが出る。
• ゲームやアプリ
の反応のアニメ
ーションに似合
う。
Other Layer Subclasses
• ゲームのためのCAEAGLLayer /
CAMetalLayer
• 完全な3Dの変換のCATransformLayer
• 大きなコンテンツをスクロールの
CAScrollLayer
• UILabelと同じのようにCATextLayer
Conclusion
• UIなら、UIView直接じゃなく、CALayerだ
• もっと努力だから、最初にUIKitでやってみ
た方がいい
• ちゃんと使えば、60FPSでかっこういいエ
フェクトが可能性になる
• 一緒に見事なアプリを作ろう!
Thanks for watching!
Thanks for watching!
to@realm.io @TimOliverAU

More Related Content

Viewers also liked

20 iOS developer interview questions
20 iOS developer interview questions20 iOS developer interview questions
20 iOS developer interview questionsArc & Codementor
 
iOS Developer Interview Questions
iOS Developer Interview QuestionsiOS Developer Interview Questions
iOS Developer Interview QuestionsClark Davidson
 
MidiMobilités Actualités #18 – Avril 2015
MidiMobilités Actualités #18 – Avril 2015MidiMobilités Actualités #18 – Avril 2015
MidiMobilités Actualités #18 – Avril 2015MidiMobilités
 
Private guitar teacher los angeles
Private guitar teacher los angelesPrivate guitar teacher los angeles
Private guitar teacher los angelesZOTZinMusic
 
Polyglot Programming @ CONFESS
Polyglot Programming @ CONFESSPolyglot Programming @ CONFESS
Polyglot Programming @ CONFESSAndres Almiray
 
Responsive design lunch and learn
Responsive design lunch and learnResponsive design lunch and learn
Responsive design lunch and learnRicardo Queiroz
 
Momentsinlife
MomentsinlifeMomentsinlife
Momentsinlifepishgo
 
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)Lever Inc.
 

Viewers also liked (11)

Animation in iOS
Animation in iOSAnimation in iOS
Animation in iOS
 
20 iOS developer interview questions
20 iOS developer interview questions20 iOS developer interview questions
20 iOS developer interview questions
 
iOS Developer Interview Questions
iOS Developer Interview QuestionsiOS Developer Interview Questions
iOS Developer Interview Questions
 
MidiMobilités Actualités #18 – Avril 2015
MidiMobilités Actualités #18 – Avril 2015MidiMobilités Actualités #18 – Avril 2015
MidiMobilités Actualités #18 – Avril 2015
 
Private guitar teacher los angeles
Private guitar teacher los angelesPrivate guitar teacher los angeles
Private guitar teacher los angeles
 
Polyglot Programming @ CONFESS
Polyglot Programming @ CONFESSPolyglot Programming @ CONFESS
Polyglot Programming @ CONFESS
 
Responsive design lunch and learn
Responsive design lunch and learnResponsive design lunch and learn
Responsive design lunch and learn
 
Momentsinlife
MomentsinlifeMomentsinlife
Momentsinlife
 
Bibat museoan
Bibat museoan Bibat museoan
Bibat museoan
 
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)
Hiring for Scale; 13 Hacks in 30 Minutes (Startup Grind Europe presentation)
 
Commodity tips
Commodity tipsCommodity tips
Commodity tips
 

Similar to try! Swift - Advanced Graphics with Core Animation

Core Animation 使って見た
Core Animation 使って見たCore Animation 使って見た
Core Animation 使って見たOCHI Shuji
 
LIFULL HOME'S「かざして検索」リリースの裏側
LIFULL HOME'S「かざして検索」リリースの裏側LIFULL HOME'S「かざして検索」リリースの裏側
LIFULL HOME'S「かざして検索」リリースの裏側Takuro Hanawa
 
HTML5で作るスマホブラウザゲーム
HTML5で作るスマホブラウザゲームHTML5で作るスマホブラウザゲーム
HTML5で作るスマホブラウザゲームTakumi Ohashi
 
AI画像認識アプリ.pptx
AI画像認識アプリ.pptxAI画像認識アプリ.pptx
AI画像認識アプリ.pptxssuser3afcb9
 
scala+liftで遊ぼう
scala+liftで遊ぼうscala+liftで遊ぼう
scala+liftで遊ぼうyouku
 
Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門cocopon
 
⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2Nishida Kansuke
 
コンピュータビジョン7章資料_20140830読書会
コンピュータビジョン7章資料_20140830読書会コンピュータビジョン7章資料_20140830読書会
コンピュータビジョン7章資料_20140830読書会Nao Oec
 
静岡Developers勉強会 HTML5&CSS3
静岡Developers勉強会 HTML5&CSS3静岡Developers勉強会 HTML5&CSS3
静岡Developers勉強会 HTML5&CSS3yaju88
 
Core Animationの話 Part.1
Core Animationの話  Part.1Core Animationの話  Part.1
Core Animationの話 Part.1Yuichi Fujishige
 
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみよう
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみようJavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみよう
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみようHiroaki Wakamatsu
 
JavaScriptで『漫画カメラ』的画像加工
JavaScriptで『漫画カメラ』的画像加工JavaScriptで『漫画カメラ』的画像加工
JavaScriptで『漫画カメラ』的画像加工Masayuki Maekawa
 
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】Tomoharu ASAMI
 
Kashiwa.R#1 画像解析とパターン認識における R の利用
Kashiwa.R#1 画像解析とパターン認識における R の利用Kashiwa.R#1 画像解析とパターン認識における R の利用
Kashiwa.R#1 画像解析とパターン認識における R の利用nmaro
 
イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情takezoe
 

Similar to try! Swift - Advanced Graphics with Core Animation (20)

Core Animation 使って見た
Core Animation 使って見たCore Animation 使って見た
Core Animation 使って見た
 
Arctic.js
Arctic.jsArctic.js
Arctic.js
 
LIFULL HOME'S「かざして検索」リリースの裏側
LIFULL HOME'S「かざして検索」リリースの裏側LIFULL HOME'S「かざして検索」リリースの裏側
LIFULL HOME'S「かざして検索」リリースの裏側
 
HTML5で作るスマホブラウザゲーム
HTML5で作るスマホブラウザゲームHTML5で作るスマホブラウザゲーム
HTML5で作るスマホブラウザゲーム
 
AI画像認識アプリ.pptx
AI画像認識アプリ.pptxAI画像認識アプリ.pptx
AI画像認識アプリ.pptx
 
scala+liftで遊ぼう
scala+liftで遊ぼうscala+liftで遊ぼう
scala+liftで遊ぼう
 
Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門
 
⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2⑯jQueryをおぼえよう!その2
⑯jQueryをおぼえよう!その2
 
Hands on
Hands onHands on
Hands on
 
コンピュータビジョン7章資料_20140830読書会
コンピュータビジョン7章資料_20140830読書会コンピュータビジョン7章資料_20140830読書会
コンピュータビジョン7章資料_20140830読書会
 
静岡Developers勉強会 HTML5&CSS3
静岡Developers勉強会 HTML5&CSS3静岡Developers勉強会 HTML5&CSS3
静岡Developers勉強会 HTML5&CSS3
 
Core Animationの話 Part.1
Core Animationの話  Part.1Core Animationの話  Part.1
Core Animationの話 Part.1
 
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみよう
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみようJavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみよう
JavaScript + CSS3を活用して スマートフォンサイト/アプリに 動きを付けてみよう
 
Cocoa勉強会201208
Cocoa勉強会201208Cocoa勉強会201208
Cocoa勉強会201208
 
JavaScriptで『漫画カメラ』的画像加工
JavaScriptで『漫画カメラ』的画像加工JavaScriptで『漫画カメラ』的画像加工
JavaScriptで『漫画カメラ』的画像加工
 
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
 
Kashiwa.R#1 画像解析とパターン認識における R の利用
Kashiwa.R#1 画像解析とパターン認識における R の利用Kashiwa.R#1 画像解析とパターン認識における R の利用
Kashiwa.R#1 画像解析とパターン認識における R の利用
 
Media Kinect2014 day7
Media Kinect2014 day7Media Kinect2014 day7
Media Kinect2014 day7
 
Canvas勉強会
Canvas勉強会Canvas勉強会
Canvas勉強会
 
イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情
 

Recently uploaded

2024 01 Virtual_Counselor
2024 01 Virtual_Counselor 2024 01 Virtual_Counselor
2024 01 Virtual_Counselor arts yokohama
 
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見Shumpei Kishi
 
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~arts yokohama
 
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法ssuser370dd7
 
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)ssuser539845
 
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-LoopへTetsuya Nihonmatsu
 
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦Sadao Tokuyama
 
20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdfAyachika Kitazaki
 
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfTaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfMatsushita Laboratory
 

Recently uploaded (12)

2024 01 Virtual_Counselor
2024 01 Virtual_Counselor 2024 01 Virtual_Counselor
2024 01 Virtual_Counselor
 
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
 
2024 04 minnanoito
2024 04 minnanoito2024 04 minnanoito
2024 04 minnanoito
 
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
 
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
 
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
 
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
 
2024 03 CTEA
2024 03 CTEA2024 03 CTEA
2024 03 CTEA
 
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦
ARスタートアップOnePlanetの Apple Vision Proへの情熱と挑戦
 
20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf
 
What is the world where you can make your own semiconductors?
What is the world where you can make your own semiconductors?What is the world where you can make your own semiconductors?
What is the world where you can make your own semiconductors?
 
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfTaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
 

try! Swift - Advanced Graphics with Core Animation

  • 1. Advanced Graphics with Core Animation ティム•オリバー
  • 2. • Core Animationのアニメーションの実装方 法 • Core Animationを少し紹介する • CALayer のスブクラスの利用方法 Overview
  • 3. @TimOliverAU • 2015年3月Realmに入った • オーストラリアのパースの出 身 • iOS開発をやってるのは約6年 間 • カラオケが大好き!
  • 5. My Relation with Japan • 帰国してから日本語の勉強を始め た • 1996年に千葉県の小学校入学 • 2007年、新潟県のスキー場で ワーホリ • 2013年、pixivでiOS開発
  • 7. iComics • とんでもない画像データ • DRMフリー•コミック•リーダ ー • Core Animationを結構利 用している • (おまけに、Realmも! ^_^)
  • 9. © Apple Inc. • UIKitから下のレベル What’s Core Animation? • オペレーションをGPUに 転送させている • UIViewと深くつながって る • iOSのグラフィクもアニ メーションも管理する
  • 11. Why is it good to know? • iOSのグラフィックス•システムをもっと理解でき る • 60FPSをもっと簡単に目指す事ができる! • UIViewのAPIより、もっときれい、もっと複 雑なアニーションが可能性になる • というわけで、アプリが他にも目立つ!
  • 12. What about Core Graphics?
  • 13. override func drawRect(_ rect: CGRect) { //// General Declarations let context = UIGraphicsGetCurrentContext() //// Color Declarations let fillColor = UIColor(red: 0.808, green: 0.000, blue: 0.000, alpha: 1.000) //// Oval Drawing let ovalPath = UIBezierPath(ovalInRect: CGRectMake(9, 8, 494, 494)) fillColor.setFill() ovalPath.fill() //// Bezier Drawing let bezierPath = UIBezierPath() bezierPath.moveToPoint(CGPointMake(334.34, 360.7)) bezierPath.addCurveToPoint(CGPointMake(196.21, 362.32), controlPoint1: CGPointMake(297.59, 381.88), controlPoint2: CGPointMake(247.05, 384.06)) bezierPath.addCurveToPoint(CGPointMake(99, 279.29), controlPoint1: CGPointMake(155.05, 344.84), controlPoint2: CGPointMake(120.9, 314.25)) bezierPath.addCurveToPoint(CGPointMake(134.91, 301.14), controlPoint1: CGPointMake(109.51, 288.03), controlPoint2: CGPointMake(121.77, 295.02)) bezierPath.addCurveToPoint(CGPointMake(276.84, 301.2), controlPoint1: CGPointMake(187.41, 325.7), controlPoint2: CGPointMake(239.9, 324.01)) bezierPath.addCurveToPoint(CGPointMake(276.79, 301.14), controlPoint1: CGPointMake(276.82, 301.18), controlPoint2: CGPointMake(276.8, 301.16)) bezierPath.addCurveToPoint(CGPointMake(146.29, 165.67), controlPoint1: CGPointMake(224.24, 260.93), controlPoint2: CGPointMake(179.57, 208.49)) bezierPath.addCurveToPoint(CGPointMake(128.78, 142.08), controlPoint1: CGPointMake(139.29, 158.68), controlPoint2: CGPointMake(134.03, 149.94)) bezierPath.addCurveToPoint(CGPointMake(255.76, 238.22), controlPoint1: CGPointMake(169.06, 178.78), controlPoint2: CGPointMake(233, 225.1)) bezierPath.addCurveToPoint(CGPointMake(166.43, 126.34), controlPoint1: CGPointMake(207.6, 187.52), controlPoint2: CGPointMake(164.68, 124.6)) bezierPath.addCurveToPoint(CGPointMake(313.57, 246.95), controlPoint1: CGPointMake(242.63, 203.25), controlPoint2: CGPointMake(313.57, 246.95)) bezierPath.addCurveToPoint(CGPointMake(319.19, 250.36), controlPoint1: CGPointMake(315.92, 248.27), controlPoint2: CGPointMake(317.73, 249.37)) bezierPath.addCurveToPoint(CGPointMake(323.2, 238.22), controlPoint1: CGPointMake(320.72, 246.46), controlPoint2: CGPointMake(322.07, 242.41)) bezierPath.addCurveToPoint(CGPointMake(290.8, 101), controlPoint1: CGPointMake(335.47, 193.64), controlPoint2: CGPointMake(321.46, 142.95)) bezierPath.addCurveToPoint(CGPointMake(386.26, 291.53), controlPoint1: CGPointMake(361.74, 143.82), controlPoint2: CGPointMake(403.78, 224.23)) bezierPath.addCurveToPoint(CGPointMake(384.77, 296.89), controlPoint1: CGPointMake(385.8, 293.34), controlPoint2: CGPointMake(385.3, 295.13)) bezierPath.addCurveToPoint(CGPointMake(385.38, 297.65), controlPoint1: CGPointMake(384.97, 297.14), controlPoint2: CGPointMake(385.18, 297.39)) bezierPath.addCurveToPoint(CGPointMake(406.4, 378.93), controlPoint1: CGPointMake(420.41, 341.35), controlPoint2: CGPointMake(410.78, 387.67)) bezierPath.addCurveToPoint(CGPointMake(334.34, 360.7), controlPoint1: CGPointMake(387.4, 341.82), controlPoint2: CGPointMake(352.22, 353.17)) bezierPath.closePath() bezierPath.miterLimit = 4; UIColor.whiteColor().setFill() bezierPath.fill() //// Text Drawing let textRect = CGRectMake(35, 144, 50, 140) let textTextContent = NSString(string: "{") let textStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle textStyle.alignment = .Left let textFontAttributes = [NSFontAttributeName: UIFont.systemFontOfSize(107), NSForegroundColorAttributeName: UIColor.whiteColor(), NSParagraphStyleAttributeName: textStyle] let textTextHeight: CGFloat = textTextContent.boundingRectWithSize(CGSizeMake(textRect.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: textFontAttributes, context: nil).size.height CGContextSaveGState(context) CGContextClipToRect(context, textRect); textTextContent.drawInRect(CGRectMake(textRect.minX, textRect.minY + (textRect.height - textTextHeight) / 2, textRect.width, textTextHeight), withAttributes: textFontAttributes) CGContextRestoreGState(context) //// Text 2 Drawing let text2Rect = CGRectMake(440, 143, 50, 140) let text2TextContent = NSString(string: "}") let text2Style = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle text2Style.alignment = .Left let text2FontAttributes = [NSFontAttributeName: UIFont.systemFontOfSize(107), NSForegroundColorAttributeName: UIColor.whiteColor(), NSParagraphStyleAttributeName: text2Style] let text2TextHeight: CGFloat = text2TextContent.boundingRectWithSize(CGSizeMake(text2Rect.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: text2FontAttributes, context: nil).size.height CGContextSaveGState(context) CGContextClipToRect(context, text2Rect); text2TextContent.drawInRect(CGRectMake(text2Rect.minX, text2Rect.minY + (text2Rect.height - text2TextHeight) / 2, text2Rect.width, text2TextHeight), withAttributes: text2FontAttributes) CGContextRestoreGState(context) }
  • 15. PaintCode on the Mac App
  • 16. So. Core Animation? import QuartzCore let newLayer = CALayer() newLayer.frame = CGRectMake(0, 0, 100, 100) newLayer.backgroundColor = UIColor.redColor().CGColor • レイヤ•オブジェクトの階層で実装 • 基本的なクラスは CALayer
  • 17. So. Core Animation? import QuartzCore let newLayer = CALayer() newLayer.frame = CGRectMake(0, 0, 100, 100) newLayer.backgroundColor = UIColor.redColor().CGColor newLayer.cornerRadius = 10 • レイヤ•オブジェクトの階層で実装 • 基本的なクラスは CALayer
  • 18. CALayer Where is it in UIKit? UIViewUIView
  • 19. CALayer Where is it in UIKit? public class UIView { public var layer: CALayer { get } } UIView
  • 20. Deeply integrated with UIView public class UIView { public var frame: CGRect { get { return self.layer.frame } set { self.layer.frame = newValue } } } let newLayer = CALayer() view.layer.addSublayer(newLayer) • CALayerプロパティーが UIViewで示されてる • ‘frame’ は CALayerの ‘position’ と‘bounds’ プロパ ティーで計っている.
  • 21. Why is it not a superclass? • UIViewのlayerのクラスが変わる事もある。 • 普通のサブクラスの実装で不可能 public class MyGradientClass : UIView { override class func layerClass() -> AnyClass { return CAGradientLayer.self } }
  • 22. Mapping contents to CALayer let trySwiftLogo = self.trySwiftLogo() as UIImage let trySwiftLayer = CALayer() trySwiftLayer.contents = trySwiftLogo.CGImage (アニメーションも可!)
  • 23. Managing the scale of CALayer contentstrySwiftLayer.contentsGravity kCAGravityResize kCAGravityResizeAspectFill kCAGravityResizeAspect kCAGravityCenter
  • 26. Bitmap sampling in CALayer trySwiftLayer.minificationFilter trySwiftLayer.magnificationFilter kCAFilterTrilinear Best Quality (Slowest) kCAFilterLinear Default kCAFilterNearest Lowest Quality (Fast)
  • 28. Masking CALayer Objects let myLayer = CALayer() myLayer.contents = self.makeRedCircleImage().CGImage let myMask = CALayer() myMask.contents = self.makeMaskImage().CGImage myLayer.mask = myMask + = myLayer myMask
  • 29. Device Layer Pages Layer Arrow Layer Mask Layer
  • 30. Adding Shadows to CALayer let myLayer = view.layer myLayer.shadowColor = UIColor.blackColor().CGColor myLayer.shadowOpacity = 0.75 myLayer.shadowOffset = CGSizeMake(5, 10) myLayer.shadowRadius = 10 // IMPORTANT FOR PERFORMANCE let myShadowPath = UIBezierPath(roundedRect: view.bounds, cornerRadius: 10) myLayer.shadowPath = myShadowPath.CGPath
  • 31. Transforming a CALayer let myLayer = CALayer() myLayer.contents = self.makeTrySwiftLogoImage().CGImage var transform = CATransform3DIdentity transform.m34 = 1.0 / -500 transform = CATransform3DRotate(transform, 45.0f * M_PI / 180.0, 0, 1, 0) myLayer.transform = transform
  • 34. Blend Modes with CALayer let myBlendLayer = CALayer() myBlendLayer.setValue(false, forKey: “allowsGroupBlending”) // PRIVATE myBlendLayer.compositingFilter = “screenBlendMode" myBlendLayer.allowsGroupOpacity = false myLayer.addSublayer(myBlendLayer) • 注意:Private APIを利用している! + =
  • 35. CALayer - “destIn” Blend Mode CALayer - “screenBlendMode” Blend ModeCALayer - “linearLightBlendMode” Blend ModeCAGradientLayer - “colorDodgeBlendMode” Blend Mode CALayer - “multiplyBlendMode” Blend Mode CAShapeLayer - Normal Blend Mode
  • 37. Animating with Core Animation
  • 38. Compared to UIKit let trySwiftView = UIImageView(image:) let trySwiftView.center = CGPointZero UIView.animateWithDuration(2, delay: 0, options: .CurveEaseInOut, animations: { trySwiftView.center = CGPointMake(0, 500) }, completion: nil)
  • 39. CABasicAnimation let trySwiftLayer = //… let myAnimation = CABasicAnimation(keyPath: “position.x”) myAnimation.duration = 2 myAnimation.fromValue = trySwiftLayer.position.x myAnimation.toValue = trySwiftLayer.position.x + 500 myAnimation.timingFunction = kCAMediaTimingFunctionEaseInEaseOut myAnimation.repeatCount = .infinity trySwiftLayer.addAnimation(myAnimation, forKey: “myAnimationKeyName”)
  • 40. CABasicAnimation let trySwiftLayer = //… let myAnimation = CABasicAnimation(keyPath: “position.x”) myAnimation.duration = 2 myAnimation.fromValue = trySwiftLayer.position.x myAnimation.toValue = trySwiftLayer.position.x + 500 myAnimation.timingFunction = kCAMediaTimingFunctionEaseInEaseOut myAnimation.repeatCount = .infinity trySwiftLayer.addAnimation(myAnimation, forKey: “myAnimationKeyName”)
  • 41. Timing Function let timingFunction = CAMediaTimingFunction(controlPoints: .08, .04, .08, .99) let myAnimation = CABasicAnimation() myAnimation.timingFunction = timingFunction http://cubic-bezier.com
  • 42. Animating a CALayer’s Contents let imageView = UIImageView() let onImage = UIImage() let offImage = UIImage() let myAnim = CABasicAnimation(keyPath: “contents”) myAnim.fromValue = offImage.CGImage myAnim.toValue = onImage.CGImage myAnim.duration = 0.15 imageView.layer.addAnimation(myCrossfadeAnimation, forKey: “contents”) imageView.image = onImage
  • 43. CAKeyframeAnimation let rect = CGRectMake(0, 0, 200, 200) let circlePath = UIBezierPath(ovalInRect:rect) let circleAnimation = CAKeyframeAnimation() circleAnimation.keyPath = “position” circleAnimation.path = circlePath.CGPath circleAnimation.duration = 4 // Manually specify keyframe points // circleAnimation.values = //… // circleAnimation.keyTimes = //.. let trySwiftLayer = //… trySwiftLayer.addAnimation(circleAnimation, forKey: “position”)
  • 44. CAAnimationGroup let myPositionAnimation = CABasicAnimation.animation(keyPath: “position”) let myAlphaAnimation = CABasicAnimation.animation(keyPath: “opacity”) let animationGroup = CAAnimationGroup() animationGroup.timingFunction = kCAMediaTimingFunctionEaseInEaseOut animationGroup.duration = 2 animationGroup.animations = [myPositionAnimation, myAlphaAnimation] let trySwiftLayer = CALayer() trySwiftLayer.addAnimation(animationGroup, forKey: “myAnimations”)
  • 45. Animation Completion Handling // Set a delegate object let myAnimation = CABasicAnimation() myAnimation.delegate = self // Animation completion sent to ‘animationDidStop(anim: finished flag:) // ——— //Set a closure to be executed at the end of this transaction CATransaction.begin() CATransaction.setCompletionBlock({ // Logic to be performed, post animation }) CATransaction.commit()
  • 47. Features of Core Animation Subclasses
  • 48. Features of Core Animation Subclasses • UIViewのサブクラスで入れる • GPUで実行、特別なイフェクト • 時々、CPUのオペレーションもある public class MyGradientClass : UIView { override class func layerClass() -> AnyClass { return CAGradientLayer.self } }
  • 51. CAReplicaterLayer © iNVASIVECODE 2015 https://vimeo.com/128046096 • GPUで一つのレイヤを 何回もコピーして表示 する • サムネールやゲームで も役に立つ
  • 52. CAShapeLayer UAProgressView © Urban Apps 2014 • CGPathから色々な形が表示 させ、アニメーションさせる • 読み込むアイコンにとても合って る •iOS 7のデザインスタイルにも似合って る
  • 53. CAEmitterLayer Particle Playground on the Mac App Store • レイヤの’frame’ からパーティク ルが出る。 • ゲームやアプリ の反応のアニメ ーションに似合 う。
  • 54. Other Layer Subclasses • ゲームのためのCAEAGLLayer / CAMetalLayer • 完全な3Dの変換のCATransformLayer • 大きなコンテンツをスクロールの CAScrollLayer • UILabelと同じのようにCATextLayer
  • 55. Conclusion • UIなら、UIView直接じゃなく、CALayerだ • もっと努力だから、最初にUIKitでやってみ た方がいい • ちゃんと使えば、60FPSでかっこういいエ フェクトが可能性になる • 一緒に見事なアプリを作ろう!

Editor's Notes

  1. Good morning / afternoon! Welcome to Advanced Graphics with Core Animation! Time is short, so let’s get started
  2. Alrighty. We’re going to be covering three major points today First: So we’re all on the same page, a general introduction to Core Animation, and how it differs to UIKit. Second: How to set up and perform animations in Core Animation Third: A quick walkthrough on some of the CALayer subclasses available to us on iOS.
  3. Before we get started, let me introduce myself! My name’s Tim Oliver and I’m an engineer from Perth in Western Australia. In the past, I’ve worked for both web and app design and development agencies, but I now work full-time for Realm, having started in March last year. I’ve been a huge fan of developing iOS apps since the iPhone 3G launched in Australia, and I’ve been doing iOS development in a professional capacity since mid-2009. Also, I love karaoke. Let me know if there’s plans for doing that after this! ;D
  4. I also really like bad puns. :D
  5. I feel I should also mention my relationship with Japan. I love Japan and I’ve been coming here for… a while. Due to my father’s work, my family lived in Japan in 1996 where we made many friends and connections. My sister and I have been studying the language in Australia ever since. Since 1996, I’ve also lived in Japan twice since then: in 2007 when I did a working holiday in Niigata and Osaka, and in 2013 when I worked as a developer for a company named pixiv.
  6. In my free time, I’m building a comic reader app named iComics.
  7. In my free time, I’m building a comic reader app named iComics. The goal of the app being where users can read their own digital comics on their devices. Obviously the app is incredibly graphics heavy, and so I’ve spent many months playing with various features of UIKit and Core Animation in my goal of a constant 60FPS. This talk is going to be mostly around what I’ve learned from all of this ‘playing’. Additionally, iComics is powered by Realm, making me the only employee of Realm using it in a shipping app. Spoiler-alert: it’s really good!
  8. So let’s get started! I’m not really sure what level everyone here is at, so I’m hoping these first few slides won’t be too boring for everyone. What exactly is Core Animation?
  9. Simply put, Core Animation is the system framework that handles both the graphics rendering, and animation of native apps on iOS. From your app, it directly handles offloading work created by the CPU, to the GPU in a low-level, efficient API. Looking at Apple’s chart, UIKit actually sits on top of it, and hooks into Core animation on a very tightly integrated level. Core Animation itself sitting directly on OpenGL, and presumably Metal since iOS 9.
  10. Similarly to UIView, Core Animation is mainly represented as a series of layer objects. which can be added to each other, just like subviews. In their most basic implementation, they are quads that are either a flat color, or can have content, such as a bitmap directly mapped to it. In my experience doing game development as a hobby, working with the graphics on this level feels very close to writing custom game UIs directly with OpenGL.
  11. But with that all being said, why should we even care about Core Animation? UIKit is all we need right? Well, that’s 95% true, but there are a lot of advantages of learning how to work with Core Animation alongside UIKit. It’s the framework actually in charge of rendering the content on your screen, and so understanding how UIKit interacts with it lets you understand what is actually going on in your app. This subsequently lets you optimise your app’s speed as it runs, allowing you to fix performance bottlenecks more easily. Another advantage is that not all of Core Animation is exposed via UIKit, so the amount of effects you can create on the GPU dramatically increases when you know how to incorporate. All of this has a really singular goal: by making animations, effects and optimising your performance, you can make an app that really stands out and impresses people.
  12. One thing I got confused at A LOT when I was originally starting out with graphics on iOS was how is Core Animation different to Core Graphics? Surely Core Animation is just the ‘animation’ part of graphics on iOS, and Core Graphics is the actual ‘rendering’ part. As it turns out that’s not true, and personally, I think Core Graphics, while relevant, is a slightly confusing name. To show the difference, here’s some code I wrote. :)
  13. A small amount of code… it took like 3 minutes to write. XD This is a mixture of Core Graphics and UIKit code. Can you guess what it does? It draws the try! Swift logo!
  14. In case you didn’t really get what just happened, Core Graphics lets you dynamically draw complex shapes and manipulate image data. This is completely different to Core Animation in that it ALL happens statically on the CPU. This sort of drawing is too complex to perform on the GPU, and so Core Graphics inherently never leaves the GPU. As a result, it can be quite slow, especially on hardware, like the A5X chip that had a CPU disproportionate to its graphics hardware. While I’ve seen a few sample projects on GitHub rely on Core Graphics to animate their content, manually performing a redraw every 1/60 seconds, this is not great since it’s slow, and taxes the CPU a lot. Instead, it’s often great to get Core Graphics and Core Animation to work together. Core Graphics can perform the initial image generation/processing, and then pass the finished content off to Core Animation, which can then manipulate it on the GPU as needed.
  15. By the way. I lied. I didn’t write that code. There’s a really nice app out there named PaintCode that lets you take vector images, like SVG and convert them into raw Core Graphics code. I use it very often for icons in my app since it you can dynamically render them at any size, minimising redundant files. I seriously recommend this app.
  16. Like I said earlier, Core Animation is a series of layer objects. Not surprisingly, the base layer class is called CALayer. Creating a layer object is a lot like creating a UIView, except all of the niceties of UIKit, like UIColor and UIImage aren’t available and needed to be converted to Core Graphics first. Additionally, it is always necessary to import the QuartzCore framework, in order to work with CALayers.
  17. And then to make it even more interesting, you can apply a very quick rounded edge mask to it via the ‘cornerRadius’ feature. We’ll look more at Core Animation masks down the line.
  18. In fact, what we actually see when we display a UIView is actually just a CALayer object! Every UIView has a CALayer ‘layer’ property, and THAT is responsible for what we see on the screen. That isn’t to say that UIView is a waste of effort. UIView add a lot of iOS’ core features such as auto-layout and gesture recognizers, and the ability to transparently configure the layer object via UIKit objects like UIColor. But all that being said, we credit the actual drawing of the view to the screen with Core Animation.
  19. 実はUIViewはCALayerで表示されています。UIViewの見える姿は完全にレイヤです。これは’layer’のプロパティーで見られます。
  20. Since CALayer is the visual component of UIView, it makes sense that all of the properties relating to layout actually map straight to the same properties in CALayer. While this probably isn’t the exact code that happens, both CALayer and UIView’s ‘frame’ property can be used interchangably. But even that being said, the ‘frame’ property of CALayer is computed by two other properties: the ‘position’ value which maps the centre point of the layer, and the bounds, which contains the size. If adding a whole new UIView might be overkill, it’s possible to create child layers of a UIVie’s layer by using the ‘addSublayer’ method. I use this a lot for elements that don’t require the additional overhead of a UIView, like a ‘dimming’ effect that only appears when a view is tapped.
  21. It’s often asked, given that UIView is basically a higher-level derivative of CALayer, why isn’t UIView simply a subclass of it? The reason for this is that UIKit provides an interesting mechanism where it’s possible to ‘swap out’ the class of a layer for a subclass that provides alternative or additional effects. This is done by overriding the ‘layerClass’ method of your own UIView subclass and providing the class reference to your CALayer subclass of choice. This wouldn’t be possible with the traditional subclass method, since it would always be locked to just CALayer then.
  22. While setting the background color of a CALayer is a good start, that’s not great for a fully fleshed out UI. Instead, CALayers have a property named ‘contents’ that can be used to map content, usually bitmaps to the layer. This is also where ‘drawRect’ on UIView objects will map to. But for the sake of demonstration, we can take the try! Swift logo we procedurally created earlier, store it as a UIImage, and then directly map it to a CALayer. The result is a very low-level, but functionally identical version of a UIImageView.
  23. Once a bitmap is mapped to a layer, it’s possible to configure how it will be rendered. By default, the bitmap will be resized to fit the frame of the layer. If the layer’s aspect ratio doesn’t match the image’s, then it will be distorted to fit. But. By changing the ‘contentsGravity’ property of the layer, it’s possible to change the behaviour of this bitmap scaling. Some of the more useful ones are ‘resize aspect fill’, where the content scales to fill the layer, or ‘aspect fit’, where the image stays at the right aspect ratio, but changes to fit the layer. I should mention, this property is also exposed via the ‘contentMode’ of UIView, so if you want to do this sort of behaviour with a UIImageView, it’s not necessary to drop to the Core Animation layer for that.
  24. If you want an example of where this sort of behaviour is useful, I absolutely recommend checking out the Tweetbot app. Hands-down, the most beautiful and elegantly designed app on iOS. When you view a Twitter account’s profile, and scroll beyond the bounds of the top, the background image grows to match the gap, but doesn’t distort. This is a much easier effect to achieve using ‘resize aspect fill’ since you only need to modify the height of the view, and keep the width constant.
  25. Another interesting application of manipulating the content gravity of a layer is a technique I came up while building the ‘page scrubber’ view in iComics. I wanted both the track of page numbers, as well as the ‘handle’ control to be transparent. Without doing a costly masking operation, I discovered it was far easier and faster to simply map a bitmap of the page numbers track to two separate layers with ‘left’ and ‘right’ gravity properties respectively, and to simply resize their frames around the position of the handle control. This created the illusion of the handle control appearing over the page numbers track, but was still transparent, allowing the background content to still come through.
  26. When I said ‘resized’ in the previous slides, I feel like I should have been more specific ‘how’. Since CALayer objects are rendered on the GPU, there’s no chance in there for the CPU to do a proper resampling pass. It’s up to the GPU to perform the bitmap rescaling. This is deferred to the texture resampling feature of the GPU itself (Now we’re REALLY entering game dev land!) via two properties: minificationFilter and magnificationFilter. By default, these properties are set to ‘linear’ which actually refers to the process known as bilinear filtering in graphics programming. This is a quick way of performing texture smoothing at different sizes, but starts to look really bad at very small sizes. Two other alternatives on iOS are ‘nearest’ and ‘trilinear’. ‘Nearest’ performs no smoothing at all and simply upscales and downscales the texels themselves. This can look utterly terrible, but is VERY fast to render, which may make it viable for certain cases. The alternative is ‘trilinear’ filtering, another term often used in game development. In this case, resized copies of the bitmap (named mipmaps) are created on the GPU and then blended together when the bitmap is scaled to certain scales. While this will definitely reduce the visual artefacts caused by bilinear filtering, it’s not great for real-time graphics like scroll views since there will be blocking on the main thread when generating the mipmaps.
  27. An example of where ‘nearest’ filtering is useful is present in an action we do on iOS everyday! When opening and closing an app, the ‘screenshot’ of the app is rendered as ‘nearest’ as it scales. This is because as it gets smaller, it cross-fades with the app icon, so it’s not very easy to see the visual artefacts, but also maintains a proper 60FPS while doing so.
  28. Another cool thing that CALayers can do is masking. Taking a CALayer, it’s possible to add another CALayer with an alpha channel as a ‘mask’. This will then clip the original CALayer to the shape of the mask. This can be used to create a wide-range of visual effects that wouldn’t otherwise be easily possible. It’s also the basis of a lot of popover views in iOS that have rounded corners.
  29. In iComics, I wanted to create a ‘tool tip view’ that visually demonstrated what effect enabling a setting would have on the UI. To do this, I used PaintCode to generate a series of bitmaps, and a masking layer. These were then blended together and animated with Core Animation to create the following effect.
  30. One very cool feature of Core Animation is the ability to add shadows to layers. While iOS 7’s visual aesthetic doesn’t rely on shadows as much as iOS 6 used to, they are still great to enhance the contrast between two elements when color alone isn’t enough. One thing of note is that it’s very important to set a CGPath to the ‘shadowPath’ property of a layer. If this isn’t done, Core Animation will determine the shape of the shadow by testing the opacity of each pixel in the layer, which is incredibly time-consuming.
  31. Another Core Animation level exclusive property I want to mention is the transform property. Unlike the transform property in UIView, the transform property of CALayer allows a full-blown 3D set of transformations. This means you can manipulate and animate views in 3D space, creating cool looking perspective views.
  32. Even though iOS 7’s design language eschews most types of 3D graphics in favour of a clean, flat design, the use of 3D translated layers are still put to good use in certain parts of the system.
  33. Another app that famously made good use of 3D transforms was ‘Flipboard’, which one iPad App of the Year in 2010. It uses 3D transforms for its transition animation when turning between pages.
  34. Finally, one cool little feature of Core Animation is the ability to blend layers on top of each other. This isn’t officially supported on iOS, and requires the use of a private API call in order to enable it. However, given that it’s simply a string property, you PROBABLY would get away with it. ;) It’s possible for CALayers to performing blending operations on top of each other to produce very interesting, dynamic visual effects.
  35. I originally discovered this when curiosity got the better of me, and I decided to deconstruct and introspect the famous iOS ‘slide to unlock’ visual effect. As it turns out, this effect is achieved through multiple layers being blended on top of each other, which creates a very visual appealling, ‘glinty’ effect
  36. On that note, another piece of software I’d like to recommend is ‘Reveal’ by Itty Bitty Apps. This OS X tool makes it very easily to introspect the visible UI of an app, as it’s running, making it very easy to debug, and tweak UIView layouts in realtime. It was invaluable in letting me deconstruct the original ‘slide to unlock’ view.
  37. Alright. Hopefully you all learned something new about Core Animation just now! :) While we’ve got the rendering aspect down now, next we’ll talk briefly about how to go about animating these layers.
  38. One strength of UIKit is its animation APIs. It’s VERY easy to setup a view animation, and Swift has further simplified the syntax with closures. For example, this is all that is needed to move a view 500 points to the left.
  39. On Core Animation’s level, creating an animation is a bit more work. This is what’s actually happening behind the scenes on the UIView level. Each ‘change’ to layer is a discrete CABasicAnimation. You create an instance of an animation object, set the before and after values, and then apply it to the layer.
  40. The animation is then applied. It is also worth noting that these changes aren’t applied to the object itself, so it’s usually necessary to update the properties of the object as well.
  41. Unless the property you’re animating isn’t explicitly animatable on the UIView level, it’s usually best to animate as much on that level. Otherwise, one of the main reasons why you might want to drop to this level is the fine level of timing control you get. By explicitly entering the points of a cubic bezier curve, you can control the exact motion curve of an animation. A great site to work out these values is cubic-bezier.com
  42. One awesome little feature of Core Animation is it’s possible to animate the ‘contents’ property of a layer. In practice, this means you can actually get a layer to perform a proper cross-fade animation between two images. This is in contrast to layering two views over each other and animating their alpha values at the same time, which would result in a brief ‘fade out’ artefact when both of the images hit ‘0.5’ in their animation cycle.
  43. Another type of animation is keyframe animations, where you can specify an array of values, and and array of time intervals that the layer will animate to within the given duration. More importantly, one extremely powerful feature of Core Animation, unavailable with UIView, is the ability to animate layers along CGPaths; in other words, along curves. This can help create much more dynamic animations, and can be used in subtle ways to improve your app’s experience.
  44. It should be apparent by now that for every animation you wish to add to a layer, a separate CAAnimation object must be created. If you want to have multiple values change in a single animation session, it’s possible to group separate animations in a single animation group.
  45. Finally, one of the more appreciated features of UIView animations is an optional closure that can be called when the animation is completed. Traditionally, in Core Animation, this has meant setting a delegate object on the CAAnimation in question, but this can end up being very messy to manage. Instead, a more modern approach is the ability to encapsulate a group of animations inside a single CATransaction, and set a completion block on it.
  46. As you can see, animating in Core Animation allows for much greater potential, but also requires a lot more code. Just like PaintCode however, certain apps exist that can help automate the amount of code generation required to pull off an effect. CoreAnimator is one that has been getting a lot of praise lately. It’s been billed as being able to help animate simple app icons, all the way up to building games. I’ve played with it a few times and it looked really promising.
  47. Finally, let’s look at some of the other CALayer types there are on iOS, and how they can be used.
  48. These layers still take advantage of the GPU, so they’re still the recommended way over Core Graphics. That being said, some of them DO rely on a Core Graphics pass on the CPU as well, which may be needed to be considered. As mentioned earlier in this talk, inserting a new CALayer subclass into a UIView is as easy as overriding the layerClass method in your subclass.
  49. Tile layers are really prominent in apps like iBooks. When placed in a scroll view and zoomed in, tile layers observe their zoom level, and at determined zoom levels, will trigger an asynchronous redraw on the CPU of their content at the current zoom level. This means for content like PDF files, the zoomed in, visible portion can be redrawn at a higher resolution. Additionally, tile layers cache these zoomed-in bitmaps and are very efficient at re-using them.
  50. Gradient layers do exactly what they say. By providing an array of colours and an array of points, it’s possible to dynamically render a gradient pattern into a layer. This can be used for really good subtle effects. For example, in Safari’s tab view, not only are the layers there being translated into 3D, they also have a subtle dark gradient applied which enhances their depth.
  51. Replicator layers are incredibly efficient. All you need to do is provide a single layer, and the replicator layer will duplicate it on the GPU. This means being able to have a huge number of layers on-screen, without the performance hit you’d suffer managing all of those on the CPU. The replicated layers can be modified in terms of their colour and position, but sadly not their contents. As such, this might be useful for games or a 3D column of thumbnails, but not really useful elsewhere.
  52. Shape Layers are incredibly useful, and the effect they can produce is very prevalent on iOS 7. By providing a CGPath, it’s possible to get the shape layer to either fill the path, or stroke it with a line. This has most commonly been used for effects such as the loading indicator for apps in the App Store.
  53. Most likely spawning from the smoke effects on OS X, emitter layers let you create a layer that displays a series of animated, emitted particles. This emission pattern can be very finely controlled, and depending on the texture used, a wide variety of effects is possible. There may be a few instances in an app UI where this effect might be useful, but I can say it’s definitely useful for game UIs.
  54. Apart from that, there are a few other layers worth mentioning. CATextLayer - Similar to a UILabel in that it renders text to the layer. CAScrollLayer - Scrolls large amounts of content. This is probably more useful on OS X than iOS on account of having UIScrollView. CATransformLayer - A layer that converts the transformation space into proper 3D. CAEAGLLayer / CAMetalLayer - The layers that render commands from the OpenGL/Metal APIs. Used as the entry point for game engines.
  55. And there we have it! Hopefully you learned something new!
  56. Thanks a lot for watching! And I hope you have an enjoyable week!