Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift Animation
Search
Yuto Akiba
December 07, 2016
Programming
280
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swift Animation
Yuto Akiba
December 07, 2016
More Decks by Yuto Akiba
See All by Yuto Akiba
実践 Dev Containers × Claude Code
touyu
1
1.4k
サーバーレスで構築するBreaking Down LIVE
touyu
2
110
スタートアップにおける TiDB Serverless の導入
touyu
1
53
Other Decks in Programming
See All in Programming
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
110
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
1
170
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
220
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
120
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
260
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
150
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
250
20260623_Loop Engineeringで自分の分身の問い合わせBotを作る
ryugen04
0
200
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
220
なぜ関数型プログラミングで「型」と「証明」が語られるのか #fp_matsuri
kajitack
3
800
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
4k
1年で人数1.5倍、PR数5.5倍増。 品質とアウトカムはどうなったか、 何が効いたか
ike002jp
0
120
Featured
See All Featured
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
420
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
HDC tutorial
michielstock
2
740
4 Signs Your Business is Dying
shpigford
187
22k
Code Reviewing Like a Champion
maltzj
528
40k
Thoughts on Productivity
jonyablonski
76
5.2k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1k
Writing Fast Ruby
sferik
630
63k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
460
Faster Mobile Websites
deanohume
310
32k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
970
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Transcript
Swift Animation Yuto Akiba (@akkey0222)
ࣗݾհ • ळ༿ ༞ਓ(Yuto Akiba) • @akkey0222 • ໋ཱؗେֶ ใཧֶ෦
2ճੜ • झຯΞϧόΠτͰiOSΞϓϦΛ։ൃ
ϦϦʔεதͷΞϓϦ R-Portable Librarian
Ξχϝʔγϣϯͱ͍͑ɺ
UIView.animateWithDuration UIView.animateWithDuration(1.0, animations: { })
UIView.animateWithDuration UIView.animateWithDuration(1.0, animations: { }) ͍·ͤΜʂʂ
͡Ό͋ɺͳʹΛ͏ʁ
Core Animation
ͲΜͳ͜ͱ͕Ͱ͖Δʁ
iOSͷϩοΫը໘෩ͷ จࣈͷΞχϝʔγϣϯ ϚςϦΞϧσβΠϯ෩ ϘλϯͷΞχϝʔγϣϯ 3D Ξχϝʔγϣϯ
͍ΖΜͳϦονͳ ΞχϝʔγϣϯΛ࡞ΕΔʂ
1.iOSͷϩοΫը໘෩ͷจࣈͷΞχϝʔγϣϯ 2.3D Ξχϝʔγϣϯ
iOSͷϩοΫը໘෩ͷ จࣈͷΞχϝʔγϣϯ
CALayerͱMask
+ → let blueLayer = CALayer() let blueImage = UIImage(named:
"blue") blueLayer.contents = blueImage?.CGImage let twitterMask = CALayer() let twitterImage = UIImage(named: "twitter") twitterMask.contents = twitterImage?.CGImage blueLayer.mask = twitterMask blueLayer twitterMask
CALayerΛ͏ͱ ؆୯ʹMaskͰ͖Δ
จࣈͷΞχϝʔγϣϯ ʹMaskΛར༻ʂ
slide to unlock CALayer CAGradientLayer
CALayerΛͬͯจࣈྻΛඳը // จࣈྻΛը૾ʹม let text = "slide to unlock" UIGraphicsBeginImageContextWithOptions(frame.size,
false, 0) text.drawInRect(bounds, withAttributes: textAttributes) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() // ը૾ΛCALayerʹม let maskLayer = CALayer() maskLayer.backgroundColor = UIColor.clearColor().CGColor maskLayer.frame = CGRectOffset(bounds, bounds.size.width, 0) maskLayer.contents = image.CGImage
CAGradientLayerͷੜ let gradientLayer = CAGradientLayer() // άϥσʔγϣϯͷઃఆ gradientLayer.startPoint = CGPoint(x:
0.0, y: 0.5) gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5) let colors = [UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0).CGColor, UIColor.whiteColor().CGColor, UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0).CGColor] gradientLayer.colors = colors let locations = [0.25, 0.5, 0.75] gradientLayer.locations = locations
CAGradientLayerͷΞχϝʔγϣϯ // Animationͷઃఆ let gradientAnimation = CABasicAnimation(keyPath: "locations") gradientAnimation.fromValue =
[-0.25, -0.25, 0.00] gradientAnimation.toValue = [1.00, 1.25, 1.25] gradientAnimation.duration = 2.0 gradientAnimation.repeatCount = Float.infinity gradientAnimation.removedOnCompletion = false gradientAnimation.fillMode = kCAFillModeForwards gradientLayer.addAnimation(gradientAnimation, forKey: nil)
ຊདྷͷߏͬͱෳࡶ (try! swiftͷTim Oliver͞ΜͷൃදΛࢀর)
1.iOSͷϩοΫը໘෩ͷจࣈͷΞχϝʔγϣϯ 2.3D Ξχϝʔγϣϯ
3DΞχϝʔγϣϯ
None
func tapedImageView() { var transform = CATransform3DIdentity // ԕۙײ transform.m34
= -1.0 / 500 // ֯ let angle = -15.0 / 180.0 * CGFloat(M_PI) transform = CATransform3DRotate(transform, angle, 1, 0, 0) // Ξχϝʔγϣϯͷઃఆ let animation = CABasicAnimation(keyPath: "transform") animation.toValue = NSValue(CATransform3D: transform) animation.duration = 0.2 animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards imageView.layer.addAnimation(animation, forKey: "transform") // Ξχϝʔγϣϯͷ։࢝ imageView.layer.setAnchorPoint(CGPoint(x: 0.5, y: 0) , forView: view) }
func tapedImageView() { var transform = CATransform3DIdentity // ԕۙײ transform.m34
= -1.0 / 500 // ֯ let angle = -15.0 / 180.0 * CGFloat(M_PI) transform = CATransform3DRotate(transform, angle, 1, 0, 0) // Ξχϝʔγϣϯͷઃఆ let animation = CABasicAnimation(keyPath: "transform") animation.toValue = NSValue(CATransform3D: transform) animation.duration = 0.2 animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards imageView.layer.addAnimation(animation, forKey: "transform") // Ξχϝʔγϣϯͷ։࢝ imageView.layer.setAnchorPoint(CGPoint(x: 0.5, y: 0) , forView: view) }
m34ͬͯԿʁ (ಡΈํΘ͔Βͳ͍…)
None
AppleͷυΩϡϝϯτΛ ݟΔͱ…
None
ߦྻͷΒ͍͠
ߦྻͱ࠲ඪͷม
͔͜͜Βͪΐͬͱ ֶతͳ
Ҡಈ มޙͷ࠲ඪ มલͷ࠲ඪ Ҡಈྔ xํʹtx, yํʹtyҠಈͤ͞Δ
֦େɺॖখ มޙͷ࠲ඪ มલͷ࠲ඪ ഒ xํʹsxഒ, yํʹsyഒ֦େ(ॖখ)
ճస A(x, y) α y x r rcosα rsinα
ճస A(1, 0), θ=90°ͷͱ͖ θճసͤ͞Δͱ
Ҏ্ͷ͜ͱ͔Β
ΞϑΟϯม
2࣍ݩͷͱ͖ಉ༷ʹ 3࣍ݩΛߟ͑Δͱ
ΞϑΟϯม
None
m34 = tz
m34z࣠ํͷ ҠಈྔΛࢦ͍ͯ͠ΔΒ͍͠
ҰൠతͳมͰm**Λ ૢ࡞͢Δඞཁͳ͍
func tapedImageView() { var transform = CATransform3DIdentity // ԕۙײ transform.m34
= -1.0 / 500 // ֯ let angle = -15.0 / 180.0 * CGFloat(M_PI) transform = CATransform3DRotate(transform, angle, 1, 0, 0) // Ξχϝʔγϣϯͷઃఆ let animation = CABasicAnimation(keyPath: "transform") animation.toValue = NSValue(CATransform3D: transform) animation.duration = 0.2 animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards imageView.layer.addAnimation(animation, forKey: "transform") // Ξχϝʔγϣϯͷ։࢝ imageView.layer.setAnchorPoint(CGPoint(x: 0.5, y: 0) , forView: imageView) }
func tapedImageView() { var transform = CATransform3DIdentity // ԕۙײ transform.m34
= -1.0 / 500 // ֯ let angle = -15.0 / 180.0 * CGFloat(M_PI) transform = CATransform3DRotate(transform, angle, 1, 0, 0) // Ξχϝʔγϣϯͷઃఆ let animation = CABasicAnimation(keyPath: "transform") animation.toValue = NSValue(CATransform3D: transform) animation.duration = 0.2 animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards imageView.layer.addAnimation(animation, forKey: "transform") // Ξχϝʔγϣϯͷ։࢝ imageView.layer.setAnchorPoint(CGPoint(x: 0.5, y: 0) , forView: imageView) }
extension CALayer { func setAnchorPoint(newAnchorPoint: CGPoint, forView view: UIView) {
var newPoint = CGPointMake(self.bounds.size.width * newAnchorPoint.x, self.bounds.size.height * newAnchorPoint.y) var oldPoint = CGPointMake(self.bounds.size.width * self.anchorPoint.x, self.bounds.size.height * self.anchorPoint.y) newPoint = CGPointApplyAffineTransform(newPoint, view.transform) oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform) var position = self.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y position.x = newPoint.x position.y = newPoint.y self.anchorPoint = newAnchorPoint self.position = position } }
AnchorPointͱ?
AnchorPoint = Ξχϝʔγϣϯͷத৺
None
func tapedImageView() { var transform = CATransform3DIdentity // ԕۙײ transform.m34
= -1.0 / 500 // ֯ let angle = -15.0 / 180.0 * CGFloat(M_PI) transform = CATransform3DRotate(transform, angle, 1, 0, 0) // Ξχϝʔγϣϯͷઃఆ let animation = CABasicAnimation(keyPath: "transform") animation.toValue = NSValue(CATransform3D: transform) animation.duration = 0.2 animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards imageView.layer.addAnimation(animation, forKey: "transform") // Ξχϝʔγϣϯͷ։࢝ imageView.layer.setAnchorPoint(CGPoint(x: 0.5, y: 0) , forView: imageView) }
(0.5, 0)
None
anchorPointͷ
imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
None
imageViewͷҐஔ มΘͬͯ͠·͏…
extension CALayer { func setAnchorPoint(newAnchorPoint: CGPoint, forView view: UIView) {
var newPoint = CGPointMake(self.bounds.size.width * newAnchorPoint.x, self.bounds.size.height * newAnchorPoint.y) var oldPoint = CGPointMake(self.bounds.size.width * self.anchorPoint.x, self.bounds.size.height * self.anchorPoint.y) newPoint = CGPointApplyAffineTransform(newPoint, view.transform) oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform) var position = self.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y position.x = newPoint.x position.y = newPoint.y self.anchorPoint = newAnchorPoint self.position = position } }
anchorPointͷҠಈʹ߹Θͤͯ positionΛҠಈͤͯ͞૬ࡴ
·ͱΊ
ͪΐͬͱ͍͚͜͠Ͳ ϦονͳΞχϝʔγϣϯ͕ ࡞Εָ͍ͯ͠
͋Γ͕ͱ͏͍͟͝·ͨ͠