Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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.5k
サーバーレスで構築するBreaking Down LIVE
touyu
2
110
スタートアップにおける TiDB Serverless の導入
touyu
1
57
Other Decks in Programming
See All in Programming
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
490
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
280
海上で動くGoサーバー: goroutineとchannelでさばく航行データストリーム
atsuki_seo
0
730
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
210
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
150
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
120
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
120
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2k
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
560
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
5
3.3k
Are APIs Still Relevant in the AI Era?
soyuka
0
250
Featured
See All Featured
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
990
Thoughts on Productivity
jonyablonski
76
5.4k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
430
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
600
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
500
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
300
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
500
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
400
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ΛҠಈͤͯ͞૬ࡴ
·ͱΊ
ͪΐͬͱ͍͚͜͠Ͳ ϦονͳΞχϝʔγϣϯ͕ ࡞Εָ͍ͯ͠
͋Γ͕ͱ͏͍͟͝·ͨ͠