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.7k
サーバーレスで構築するBreaking Down LIVE
touyu
2
120
スタートアップにおける TiDB Serverless の導入
touyu
1
59
Other Decks in Programming
See All in Programming
AI-Powered Domain-Driven Design
ziobrando
0
360
私なりのハーネスエンジニアリング ~独自の言語処理系の開発を通して~
seosoft
0
150
[2026-10-09]一枚の布で作らなくてもいい。 信頼性は「パッチワーク」で紡がれる~既存の運用と新しい可能性をつなぎ合わせてきたCREの話~
tosite
0
120
SODA - FACT BOOK(EN)
sodainc
1
190
No More NoSuchMethodError
exoego
1
120
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
1.7k
Seven New Principles of Software Engineering
yegor256
0
390
golang-bob.pdf
iwatsukayura
0
150
Modernizing iOS Apps
seyfoyun
0
140
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
3
1.3k
dotNET_vulnclicker_intro.pdf
deka_morita
0
160
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
140
Featured
See All Featured
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
960
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
77k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
880
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
70
68k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
540
How Software Deployment tools have changed in the past 20 years
geshan
2
35k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
590
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
910
The Limits of Empathy - UXLibs8
cassininazir
2
750
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ΛҠಈͤͯ͞૬ࡴ
·ͱΊ
ͪΐͬͱ͍͚͜͠Ͳ ϦονͳΞχϝʔγϣϯ͕ ࡞Εָ͍ͯ͠
͋Γ͕ͱ͏͍͟͝·ͨ͠