SlideShare una empresa de Scribd logo
1 de 95
Descargar para leer sin conexión
1
2
Animations
ON iOS
3
• Animations
• CoreAnimation: control, shape layer
• UIViewPropertyAnimator
• Advanced Animations
• Transitions
4
5
• Wrong password
• Launch
• Open Settings App
• Bluetooth
• Switch Off/On
• Back
6
0 100
view.frame.origin.x = 100
7
0 100
view.frame.origin.x = 100
8
0 100
view.frame.origin.x = 100 || time = 1.5
9
0 100
view.frame.origin.x = 100 || time = 2.5
view.frame.origin.x = 100 || time = 2.5 || curve = .easeIn
10
Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true)
{ (_) in
self.applyAnimationStep()
}
11
Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true)
{ (_) in
self.applyAnimationStep()
}
displayLink = CADisplayLink(target: self, selector:
#selector(applyAnimationStep))
displayLink.add(to: RunLoop.current, forMode:
RunLoopMode.defaultRunLoopMode)
12
Advanced Graphics and Animations for iOS Apps
13
14
CoreAnimation Timer-Based
• Optimization
• UIKit based
• Custom property animation
• State observing (< iOS10)
• Custom timing function (hi,
speed 👋 )
15
CoreAnimation Timer-Based
• CoreAnimation
• UIView animations
• UIViewPropertyAnimator (iOS 10+)
• CADisplayLink
• POP
• All other external frameworks
16
CoreAnimation
17
Alexander Zimin – Анимация в iOS
18
• Work with CALayer’s
• Shared for iOS/macOS
• Unfamiliar syntax
• Powerfull
19
let animation = CABasicAnimation(keyPath: "position.x")
animation.duration = 1
animation.fromValue = animationView.layer.position.x
animation.toValue = 50
animationView.layer.add(animation, forKey: "name")
animationView.layer.position.x = 50
20
let animation = CABasicAnimation(keyPath: "position.x")
animation.duration = 1
animation.fromValue = animationView.layer.position.x
animation.toValue = 50
animationView.layer.add(animation, forKey: "name")
animationView.layer.position.x = 50
21
Presentation Layer Modal Layer
22
0 100
23
0 100
24
0 100
view.frame.origin.x = 100
25
• CABasicAnimation
• CAKeyframeAnimation
• CAAnimationGroup
• CASpringAnimation (iOS 9+)
26
• bounds
• contents
• masksToBounds
• shadowColor
Animatable Properties (not all)
27
Control animation
28
29
animation = CABasicAnimation(keyPath: "position.y")
animation.duration = 2
animation.fromValue = label.layer.position.y
animation.toValue = 30
label.layer.add(animation, forKey: "animation2")
label.layer.speed = 0
label.layer.position.y = 30
30
label.layer.timeOffset = value * animation.duration
value from 0 to 1
31
CAShapeLayer
32
33
shapeLayer = CAShapeLayer()
animation = CABasicAnimation(keyPath: "path")
animation.fromValue = firstPath.cgPath
animation.toValue = secondPath.cgPath
34
shapeLayer = CAShapeLayer()
animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
35
36
let firstPath = UIBezierPath(
roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100),
byRoundingCorners: [.bottomRight, .topRight],
cornerRadii: CGSize(width: 30, height: 30)
)
let secondPath = UIBezierPath(
rect: CGRect(x: 100, y: 100, width: 100, height: 100)
)
37
let firstPath = UIBezierPath(
roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100),
byRoundingCorners: [.bottomRight, .topRight],
cornerRadii: CGSize(width: 30, height: 30)
)
let secondPath = UIBezierPath(
rect: CGRect(x: 100, y: 100, width: 100, height: 100)
)
38
39
40
let firstPath = UIBezierPath()
firstPath.move(to: CGPoint(x: 0, y: 0))
firstPath.addLine(to: CGPoint(x: 60, y: 0))
firstPath.addQuadCurve(to: CGPoint(x: 100, y: 40), controlPoint:
CGPoint(x: 100, y: 0))
firstPath.addLine(to: CGPoint(x: 100, y: 60))
firstPath.addQuadCurve(to: CGPoint(x: 60, y: 100), controlPoint:
CGPoint(x: 100, y: 100))
firstPath.addLine(to: CGPoint(x: 0, y: 100))
firstPath.addLine(to: CGPoint(x: 0, y: 0))
let firstPath = UIBezierPath()
firstPath.move(to: CGPoint(x: 0, y: 0))
firstPath.addLine(to: CGPoint(x: 60, y: 0))
firstPath.addQuadCurve(to: CGPoint(x: 100, y: 40), controlPoint:
CGPoint(x: 100, y: 0))
firstPath.addLine(to: CGPoint(x: 100, y: 60))
firstPath.addQuadCurve(to: CGPoint(x: 60, y: 100), controlPoint:
CGPoint(x: 100, y: 100))
firstPath.addLine(to: CGPoint(x: 0, y: 100))
firstPath.addLine(to: CGPoint(x: 0, y: 0))
41
42
43
let secondPath = UIBezierPath()
secondPath.move(to: CGPoint(x: 0, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 100))
secondPath.addLine(to: CGPoint(x: 100, y: 100))
secondPath.addLine(to: CGPoint(x: 0, y: 100))
secondPath.addLine(to: CGPoint(x: 0, y: 0))
44
let secondPath = UIBezierPath()
secondPath.move(to: CGPoint(x: 0, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 0))
secondPath.addLine(to: CGPoint(x: 100, y: 100))
secondPath.addLine(to: CGPoint(x: 100, y: 100))
secondPath.addLine(to: CGPoint(x: 0, y: 100))
secondPath.addLine(to: CGPoint(x: 0, y: 0))
45
46
47
No such property
48
49
50
let differenceInSize = label.font.pointSize /
anotherLabel.font.pointSize
self.anotherLabel.transform = CGAffineTransform(scaleX:
differenceInSize, y: differenceInSize)
self.anotherLabel.center = self.label.center
self.label.alpha = 1
self.anotherLabel.alpha = 0
51
let differenceInSize = label.font.pointSize /
anotherLabel.font.pointSize
self.anotherLabel.transform = CGAffineTransform(scaleX:
differenceInSize, y: differenceInSize)
self.anotherLabel.center = self.label.center
self.label.alpha = 1
self.anotherLabel.alpha = 0
a a
52
let differenceInSize = label.font.pointSize /
anotherLabel.font.pointSize
self.anotherLabel.transform = CGAffineTransform(scaleX:
differenceInSize, y: differenceInSize)
self.anotherLabel.center = self.label.center
self.label.alpha = 1
self.anotherLabel.alpha = 0
53
propertyAnimation = UIViewPropertyAnimator(duration: 0.5,
curve: .easeIn) {
self.label.alpha = 0
self.anotherLabel.alpha = 1
self.label.center.y = 50
self.anotherLabel.center.y = 50
self.label.transform = CGAffineTransform(scaleX: 1 /
differenceInSize, y: 1 / differenceInSize)
self.anotherLabel.transform = CGAffineTransform.identity
}
54
UIViewPropertyAnimator
55
propertyAnimation = UIViewPropertyAnimator(
duration: 1,
curve: .easeIn,
animations: {
self.view.alpha = 0
}
)
propertyAnimation.startAnimation()
56
• var isReversed: Bool { get set }
• var fractionComplete: CGFloat { get set }
• func continueAnimation(

withTimingParameters parameters:
UITimingCurveProvider?, 

durationFactor: CGFloat)
57
🕵
58
class ObservableLayer: CALayer {
override func add(_ anim: CAAnimation, forKey key: String?) {
print(anim, key)
super.add(anim, forKey: key)
}
}
59
animation = UIViewPropertyAnimator(duration: 2,
curve: .linear, animations: nil)
animation.addAnimations {
self.animationView.alpha = 0.2
}
animation.startAnimation()
animation.fractionComplete = 0.2
On Start
On Touch
60
On Start
61
<CABasicAnimation:0x610000024220; toValue =
0.20000000298023224; removedOnCompletion = 0;
delegate = <UIViewAnimationState:
0x7fe69e0094e0>; fillMode = both; timingFunction
= linear; duration = 2; fromValue = 1; keyPath =
opacity>
1
opacity
62
opacity = 1 -> 0.2
duration = 2
timingFunction = linear
<CABasicAnimation:0x610000024220; toValue =
0.20000000298023224; removedOnCompletion = 0;
delegate = <UIViewAnimationState:
0x7fe69e0094e0>; fillMode = both; timingFunction
= linear; duration = 2; fromValue = 1; keyPath =
opacity>
1
opacity
63
<CABasicAnimation:0x610000027340;
removedOnCompletion = 0; delegate =
<UIViewAnimationState: 0x7fe69e0094e0>; fillMode
= both; timingFunction = linear; duration = 2;
toValue = 100; fromValue = 0.0; keyPath =
uiFractionalProgress>
2
UIPacingAnimationForAnimatorsKey
64
<CABasicAnimation:0x610000027340;
removedOnCompletion = 0; delegate =
<UIViewAnimationState: 0x7fe69e0094e0>; fillMode
= both; timingFunction = linear; duration = 2;
toValue = 100; fromValue = 0.0; keyPath =
uiFractionalProgress>
2
UIPacingAnimationForAnimatorsKey
uiFractionalProgress = 0 -> 100
duration = 2
timingFunction = linear
(lldb) po self.presentation()?.value(forKey:
"uiFractionalProgress")
▿ Optional<Any>
65
On Touch
66
UIPacingAnimationForAnimatorsKey
2 x3
opacity
1 x3
67
UIPacingAnimationForAnimatorsKey
2 x3
opacity
1 x3
• speed = 0 

on 4 first
• beginTime = -0.398438
on 2 last
68
• By changing fractionComplete you
spamming new CABasicAnimation objects
69
Advanced Animations
70
• Receipt:
• Good Designer 👑
• AfterEffects
• Lottie + bodymovin
• Done 🎉
71
72
73
74
75
bodymovin
76
bodymovin
77
78
animationView = LOTAnimationView(name: "animation")
self.view.addSubview(animationView)
animationView.play()
animationView.animationProgress = CGFloat(sender.value)
79
80
animationView = LOTAnimationView(json: json)
81
let filepath = Bundle.main.path(forResource: "animation", ofType: "json")!
var contents = try! String(contentsOfFile: filepath)
contents = contents.replacingOccurrences(
of: "[0.6790901,0.178386,0.178386,1]",
with: “[0,0.9,0,1]"
)
contents = contents.replacingOccurrences(
of: "[0.6784314,0.1764706,0.1764706,1]",
with: “[0,0.9,0,1]"
)
let data = contents.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(
with: data,
options: []
) as? [String: Any]
animationView = LOTAnimationView(json: json)
82
let filepath = Bundle.main.path(forResource: "animation", ofType: "json")!
var contents = try! String(contentsOfFile: filepath)
contents = contents.replacingOccurrences(
of: "[0.6790901,0.178386,0.178386,1]",
with: “[0,0.9,0,1]"
)
contents = contents.replacingOccurrences(
of: "[0.6784314,0.1764706,0.1764706,1]",
with: “[0,0.9,0,1]"
)
let data = contents.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(
with: data,
options: []
) as? [String: Any]
animationView = LOTAnimationView(json: json)
83
let filepath = Bundle.main.path(forResource: "animation", ofType: "json")!
var contents = try! String(contentsOfFile: filepath)
contents = contents.replacingOccurrences(
of: "[0.6790901,0.178386,0.178386,1]",
with: “[0,0.9,0,1]"
)
contents = contents.replacingOccurrences(
of: "[0.6784314,0.1764706,0.1764706,1]",
with: “[0,0.9,0,1]"
)
let data = contents.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(
with: data,
options: []
) as? [String: Any]
animationView = LOTAnimationView(json: json)
Mutating Phase
84
let filepath = Bundle.main.path(forResource: "animation", ofType: "json")!
var contents = try! String(contentsOfFile: filepath)
contents = contents.replacingOccurrences(
of: "[0.6790901,0.178386,0.178386,1]",
with: “[0,0.9,0,1]"
)
contents = contents.replacingOccurrences(
of: "[0.6784314,0.1764706,0.1764706,1]",
with: “[0,0.9,0,1]"
)
let data = contents.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(
with: data,
options: []
) as? [String: Any]
animationView = LOTAnimationView(json: json)
85
86
87
• JSON
• Size (in both ways)
• Mutatablity
• Control
• Speed
• Progress
• Completion
• All AfterEffects magic
88
So
89
• Use CAShapeLayers
• Combine multiply layers:
• Use alpha/scale/mask/…
• Use time-based animations
90
Transitions
91
Alexander Zimin – UIViewController, откройся!
92
UIPercentDrivenInteractiveTransition
93
• Avoid time-based animations 🚀
• Implement user interactions (it’s easy 😉)
• Create delegate for your custom
animations on VCs 🔊
• Check github.com/azimin/AZTransitions 👍
94
• Offscreen rendering
95
@ZiminAlex

Más contenido relacionado

La actualidad más candente

Flushabo pr irsd.cfg
Flushabo pr irsd.cfgFlushabo pr irsd.cfg
Flushabo pr irsd.cfg
Roboku
 
YUI for control freaks - a presentation at The Ajax Experience
YUI for control freaks - a presentation at The Ajax ExperienceYUI for control freaks - a presentation at The Ajax Experience
YUI for control freaks - a presentation at The Ajax Experience
Christian Heilmann
 
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
Lucidworks
 

La actualidad más candente (20)

Animate The Web With Ember.js - Jessica Jordan
Animate The Web With Ember.js - Jessica JordanAnimate The Web With Ember.js - Jessica Jordan
Animate The Web With Ember.js - Jessica Jordan
 
Raspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFXRaspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFX
 
Ch21
Ch21Ch21
Ch21
 
Crush Candy with DukeScript
Crush Candy with DukeScriptCrush Candy with DukeScript
Crush Candy with DukeScript
 
Flushabo pr irsd.cfg
Flushabo pr irsd.cfgFlushabo pr irsd.cfg
Flushabo pr irsd.cfg
 
Exploring Canvas
Exploring CanvasExploring Canvas
Exploring Canvas
 
201707 CSE110 Lecture 13
201707 CSE110 Lecture 13   201707 CSE110 Lecture 13
201707 CSE110 Lecture 13
 
The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212
 
Python avanzado - parte 1
Python avanzado - parte 1Python avanzado - parte 1
Python avanzado - parte 1
 
Css5 canvas
Css5 canvasCss5 canvas
Css5 canvas
 
Canvas al ajillo
Canvas al ajilloCanvas al ajillo
Canvas al ajillo
 
pptuni1
pptuni1pptuni1
pptuni1
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
 
CoW Documentatie
CoW DocumentatieCoW Documentatie
CoW Documentatie
 
The Ring programming language version 1.2 book - Part 38 of 84
The Ring programming language version 1.2 book - Part 38 of 84The Ring programming language version 1.2 book - Part 38 of 84
The Ring programming language version 1.2 book - Part 38 of 84
 
YUI for control freaks - a presentation at The Ajax Experience
YUI for control freaks - a presentation at The Ajax ExperienceYUI for control freaks - a presentation at The Ajax Experience
YUI for control freaks - a presentation at The Ajax Experience
 
The Ring programming language version 1.8 book - Part 59 of 202
The Ring programming language version 1.8 book - Part 59 of 202The Ring programming language version 1.8 book - Part 59 of 202
The Ring programming language version 1.8 book - Part 59 of 202
 
Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)
 
Raphaël
RaphaëlRaphaël
Raphaël
 
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
Scorer’s Diversity Phase 2.0: Presented by Mikhail Khludnev, Grid Dynamics Inc.
 

Similar a Александр Зимин – Анимация как средство самовыражения

Exploring Canvas
Exploring CanvasExploring Canvas
Exploring Canvas
Kevin Hoyt
 
How to build a html5 websites.v1
How to build a html5 websites.v1How to build a html5 websites.v1
How to build a html5 websites.v1
Bitla Software
 
Crafting interactions with Core Animations, David Ortinau
Crafting interactions with Core Animations, David OrtinauCrafting interactions with Core Animations, David Ortinau
Crafting interactions with Core Animations, David Ortinau
Xamarin
 

Similar a Александр Зимин – Анимация как средство самовыражения (20)

Standford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, ViewsStandford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, Views
 
The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184
 
ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine
 
Макс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхМакс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложениях
 
The Ring programming language version 1.6 book - Part 67 of 189
The Ring programming language version 1.6 book - Part 67 of 189The Ring programming language version 1.6 book - Part 67 of 189
The Ring programming language version 1.6 book - Part 67 of 189
 
14709302.ppt
14709302.ppt14709302.ppt
14709302.ppt
 
AppKitでお絵描きしてみよう
AppKitでお絵描きしてみようAppKitでお絵描きしてみよう
AppKitでお絵描きしてみよう
 
The Ring programming language version 1.5.1 book - Part 61 of 180
The Ring programming language version 1.5.1 book - Part 61 of 180The Ring programming language version 1.5.1 book - Part 61 of 180
The Ring programming language version 1.5.1 book - Part 61 of 180
 
The Ring programming language version 1.10 book - Part 76 of 212
The Ring programming language version 1.10 book - Part 76 of 212The Ring programming language version 1.10 book - Part 76 of 212
The Ring programming language version 1.10 book - Part 76 of 212
 
Qt Animation
Qt AnimationQt Animation
Qt Animation
 
SwiftUI Animation - The basic overview
SwiftUI Animation - The basic overviewSwiftUI Animation - The basic overview
SwiftUI Animation - The basic overview
 
The Ring programming language version 1.8 book - Part 71 of 202
The Ring programming language version 1.8 book - Part 71 of 202The Ring programming language version 1.8 book - Part 71 of 202
The Ring programming language version 1.8 book - Part 71 of 202
 
Exploring Canvas
Exploring CanvasExploring Canvas
Exploring Canvas
 
Android Wear Essentials
Android Wear EssentialsAndroid Wear Essentials
Android Wear Essentials
 
How to build a html5 websites.v1
How to build a html5 websites.v1How to build a html5 websites.v1
How to build a html5 websites.v1
 
The Ring programming language version 1.2 book - Part 45 of 84
The Ring programming language version 1.2 book - Part 45 of 84The Ring programming language version 1.2 book - Part 45 of 84
The Ring programming language version 1.2 book - Part 45 of 84
 
The Ring programming language version 1.7 book - Part 69 of 196
The Ring programming language version 1.7 book - Part 69 of 196The Ring programming language version 1.7 book - Part 69 of 196
The Ring programming language version 1.7 book - Part 69 of 196
 
Real life XNA
Real life XNAReal life XNA
Real life XNA
 
Crafting interactions with Core Animations, David Ortinau
Crafting interactions with Core Animations, David OrtinauCrafting interactions with Core Animations, David Ortinau
Crafting interactions with Core Animations, David Ortinau
 
Angular animate
Angular animateAngular animate
Angular animate
 

Más de CocoaHeads

Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
CocoaHeads
 
Вадим Дробинин (Vadim Drobinin) — Заботимся правильно: CareKit, HealthKit и ...
Вадим Дробинин (Vadim Drobinin) —  Заботимся правильно: CareKit, HealthKit и ...Вадим Дробинин (Vadim Drobinin) —  Заботимся правильно: CareKit, HealthKit и ...
Вадим Дробинин (Vadim Drobinin) — Заботимся правильно: CareKit, HealthKit и ...
CocoaHeads
 
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
CocoaHeads
 

Más de CocoaHeads (16)

Дмитрий Котенко – Реактивный VIPER
Дмитрий Котенко – Реактивный VIPERДмитрий Котенко – Реактивный VIPER
Дмитрий Котенко – Реактивный VIPER
 
Николай Ашанин – Team Lead. Структурирование мыслей
Николай Ашанин – Team Lead. Структурирование мыслейНиколай Ашанин – Team Lead. Структурирование мыслей
Николай Ашанин – Team Lead. Структурирование мыслей
 
Кирилл Аверьянов — Кастомная кнопка: взгляд изнутри
Кирилл Аверьянов —  Кастомная кнопка: взгляд изнутриКирилл Аверьянов —  Кастомная кнопка: взгляд изнутри
Кирилл Аверьянов — Кастомная кнопка: взгляд изнутри
 
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодо...
 
Самвел Меджлумян — S3: API на Swift за пять минут
Самвел Меджлумян —  S3: API на Swift за пять минутСамвел Меджлумян —  S3: API на Swift за пять минут
Самвел Меджлумян — S3: API на Swift за пять минут
 
Александр Зимин (Alexander Zimin) — Магия Swift
Александр Зимин (Alexander Zimin) — Магия SwiftАлександр Зимин (Alexander Zimin) — Магия Swift
Александр Зимин (Alexander Zimin) — Магия Swift
 
Катерина Трофименко — Разработка фич: от флагов до a/b-тестов
Катерина Трофименко — Разработка фич: от флагов до a/b-тестовКатерина Трофименко — Разработка фич: от флагов до a/b-тестов
Катерина Трофименко — Разработка фич: от флагов до a/b-тестов
 
Андрей Володин — Как подружиться с роботом
Андрей Володин — Как подружиться с роботомАндрей Володин — Как подружиться с роботом
Андрей Володин — Как подружиться с роботом
 
Александр Зимин — Мобильные интерфейсы будущего
Александр Зимин — Мобильные интерфейсы будущегоАлександр Зимин — Мобильные интерфейсы будущего
Александр Зимин — Мобильные интерфейсы будущего
 
Николай Волосатов — Работа с крэшами библиотек
Николай Волосатов — Работа с крэшами библиотекНиколай Волосатов — Работа с крэшами библиотек
Николай Волосатов — Работа с крэшами библиотек
 
Вадим Дробинин (Vadim Drobinin) — Заботимся правильно: CareKit, HealthKit и ...
Вадим Дробинин (Vadim Drobinin) —  Заботимся правильно: CareKit, HealthKit и ...Вадим Дробинин (Vadim Drobinin) —  Заботимся правильно: CareKit, HealthKit и ...
Вадим Дробинин (Vadim Drobinin) — Заботимся правильно: CareKit, HealthKit и ...
 
Александр Зимин (Alexander Zimin) — UIViewController, откройся!
Александр Зимин (Alexander Zimin) — UIViewController, откройся!Александр Зимин (Alexander Zimin) — UIViewController, откройся!
Александр Зимин (Alexander Zimin) — UIViewController, откройся!
 
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
Сергей Пронин, Никита Кошолкин — Как мы разрабатываем App in the Air: процесс...
 
Михаил Рахманов — Promises, или почему обещания надо выполнять
Михаил Рахманов — Promises, или почему обещания надо выполнятьМихаил Рахманов — Promises, или почему обещания надо выполнять
Михаил Рахманов — Promises, или почему обещания надо выполнять
 
Александр Зимин — Оптимизация разработки
Александр Зимин — Оптимизация разработкиАлександр Зимин — Оптимизация разработки
Александр Зимин — Оптимизация разработки
 
Алина Михайлова — Как обойтись без менеджера в своем проекте
Алина Михайлова — Как обойтись без менеджера в своем проектеАлина Михайлова — Как обойтись без менеджера в своем проекте
Алина Михайлова — Как обойтись без менеджера в своем проекте
 

Último

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 

Александр Зимин – Анимация как средство самовыражения

  • 1. 1
  • 3. 3 • Animations • CoreAnimation: control, shape layer • UIViewPropertyAnimator • Advanced Animations • Transitions
  • 4. 4
  • 5. 5 • Wrong password • Launch • Open Settings App • Bluetooth • Switch Off/On • Back
  • 8. 8 0 100 view.frame.origin.x = 100 || time = 1.5
  • 9. 9 0 100 view.frame.origin.x = 100 || time = 2.5 view.frame.origin.x = 100 || time = 2.5 || curve = .easeIn
  • 10. 10 Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true) { (_) in self.applyAnimationStep() }
  • 11. 11 Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true) { (_) in self.applyAnimationStep() } displayLink = CADisplayLink(target: self, selector: #selector(applyAnimationStep)) displayLink.add(to: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
  • 12. 12 Advanced Graphics and Animations for iOS Apps
  • 13. 13
  • 14. 14 CoreAnimation Timer-Based • Optimization • UIKit based • Custom property animation • State observing (< iOS10) • Custom timing function (hi, speed 👋 )
  • 15. 15 CoreAnimation Timer-Based • CoreAnimation • UIView animations • UIViewPropertyAnimator (iOS 10+) • CADisplayLink • POP • All other external frameworks
  • 17. 17 Alexander Zimin – Анимация в iOS
  • 18. 18 • Work with CALayer’s • Shared for iOS/macOS • Unfamiliar syntax • Powerfull
  • 19. 19 let animation = CABasicAnimation(keyPath: "position.x") animation.duration = 1 animation.fromValue = animationView.layer.position.x animation.toValue = 50 animationView.layer.add(animation, forKey: "name") animationView.layer.position.x = 50
  • 20. 20 let animation = CABasicAnimation(keyPath: "position.x") animation.duration = 1 animation.fromValue = animationView.layer.position.x animation.toValue = 50 animationView.layer.add(animation, forKey: "name") animationView.layer.position.x = 50
  • 25. 25 • CABasicAnimation • CAKeyframeAnimation • CAAnimationGroup • CASpringAnimation (iOS 9+)
  • 26. 26 • bounds • contents • masksToBounds • shadowColor Animatable Properties (not all)
  • 28. 28
  • 29. 29 animation = CABasicAnimation(keyPath: "position.y") animation.duration = 2 animation.fromValue = label.layer.position.y animation.toValue = 30 label.layer.add(animation, forKey: "animation2") label.layer.speed = 0 label.layer.position.y = 30
  • 30. 30 label.layer.timeOffset = value * animation.duration value from 0 to 1
  • 32. 32
  • 33. 33 shapeLayer = CAShapeLayer() animation = CABasicAnimation(keyPath: "path") animation.fromValue = firstPath.cgPath animation.toValue = secondPath.cgPath
  • 34. 34 shapeLayer = CAShapeLayer() animation = CABasicAnimation(keyPath: "strokeEnd") animation.fromValue = 0 animation.toValue = 1
  • 35. 35
  • 36. 36 let firstPath = UIBezierPath( roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100), byRoundingCorners: [.bottomRight, .topRight], cornerRadii: CGSize(width: 30, height: 30) ) let secondPath = UIBezierPath( rect: CGRect(x: 100, y: 100, width: 100, height: 100) )
  • 37. 37 let firstPath = UIBezierPath( roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100), byRoundingCorners: [.bottomRight, .topRight], cornerRadii: CGSize(width: 30, height: 30) ) let secondPath = UIBezierPath( rect: CGRect(x: 100, y: 100, width: 100, height: 100) )
  • 38. 38
  • 39. 39
  • 40. 40 let firstPath = UIBezierPath() firstPath.move(to: CGPoint(x: 0, y: 0)) firstPath.addLine(to: CGPoint(x: 60, y: 0)) firstPath.addQuadCurve(to: CGPoint(x: 100, y: 40), controlPoint: CGPoint(x: 100, y: 0)) firstPath.addLine(to: CGPoint(x: 100, y: 60)) firstPath.addQuadCurve(to: CGPoint(x: 60, y: 100), controlPoint: CGPoint(x: 100, y: 100)) firstPath.addLine(to: CGPoint(x: 0, y: 100)) firstPath.addLine(to: CGPoint(x: 0, y: 0))
  • 41. let firstPath = UIBezierPath() firstPath.move(to: CGPoint(x: 0, y: 0)) firstPath.addLine(to: CGPoint(x: 60, y: 0)) firstPath.addQuadCurve(to: CGPoint(x: 100, y: 40), controlPoint: CGPoint(x: 100, y: 0)) firstPath.addLine(to: CGPoint(x: 100, y: 60)) firstPath.addQuadCurve(to: CGPoint(x: 60, y: 100), controlPoint: CGPoint(x: 100, y: 100)) firstPath.addLine(to: CGPoint(x: 0, y: 100)) firstPath.addLine(to: CGPoint(x: 0, y: 0)) 41
  • 42. 42
  • 43. 43 let secondPath = UIBezierPath() secondPath.move(to: CGPoint(x: 0, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 100)) secondPath.addLine(to: CGPoint(x: 100, y: 100)) secondPath.addLine(to: CGPoint(x: 0, y: 100)) secondPath.addLine(to: CGPoint(x: 0, y: 0))
  • 44. 44 let secondPath = UIBezierPath() secondPath.move(to: CGPoint(x: 0, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 0)) secondPath.addLine(to: CGPoint(x: 100, y: 100)) secondPath.addLine(to: CGPoint(x: 100, y: 100)) secondPath.addLine(to: CGPoint(x: 0, y: 100)) secondPath.addLine(to: CGPoint(x: 0, y: 0))
  • 45. 45
  • 46. 46
  • 48. 48
  • 49. 49
  • 50. 50 let differenceInSize = label.font.pointSize / anotherLabel.font.pointSize self.anotherLabel.transform = CGAffineTransform(scaleX: differenceInSize, y: differenceInSize) self.anotherLabel.center = self.label.center self.label.alpha = 1 self.anotherLabel.alpha = 0
  • 51. 51 let differenceInSize = label.font.pointSize / anotherLabel.font.pointSize self.anotherLabel.transform = CGAffineTransform(scaleX: differenceInSize, y: differenceInSize) self.anotherLabel.center = self.label.center self.label.alpha = 1 self.anotherLabel.alpha = 0 a a
  • 52. 52 let differenceInSize = label.font.pointSize / anotherLabel.font.pointSize self.anotherLabel.transform = CGAffineTransform(scaleX: differenceInSize, y: differenceInSize) self.anotherLabel.center = self.label.center self.label.alpha = 1 self.anotherLabel.alpha = 0
  • 53. 53 propertyAnimation = UIViewPropertyAnimator(duration: 0.5, curve: .easeIn) { self.label.alpha = 0 self.anotherLabel.alpha = 1 self.label.center.y = 50 self.anotherLabel.center.y = 50 self.label.transform = CGAffineTransform(scaleX: 1 / differenceInSize, y: 1 / differenceInSize) self.anotherLabel.transform = CGAffineTransform.identity }
  • 55. 55 propertyAnimation = UIViewPropertyAnimator( duration: 1, curve: .easeIn, animations: { self.view.alpha = 0 } ) propertyAnimation.startAnimation()
  • 56. 56 • var isReversed: Bool { get set } • var fractionComplete: CGFloat { get set } • func continueAnimation(
 withTimingParameters parameters: UITimingCurveProvider?, 
 durationFactor: CGFloat)
  • 58. 58 class ObservableLayer: CALayer { override func add(_ anim: CAAnimation, forKey key: String?) { print(anim, key) super.add(anim, forKey: key) } }
  • 59. 59 animation = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: nil) animation.addAnimations { self.animationView.alpha = 0.2 } animation.startAnimation() animation.fractionComplete = 0.2 On Start On Touch
  • 61. 61 <CABasicAnimation:0x610000024220; toValue = 0.20000000298023224; removedOnCompletion = 0; delegate = <UIViewAnimationState: 0x7fe69e0094e0>; fillMode = both; timingFunction = linear; duration = 2; fromValue = 1; keyPath = opacity> 1 opacity
  • 62. 62 opacity = 1 -> 0.2 duration = 2 timingFunction = linear <CABasicAnimation:0x610000024220; toValue = 0.20000000298023224; removedOnCompletion = 0; delegate = <UIViewAnimationState: 0x7fe69e0094e0>; fillMode = both; timingFunction = linear; duration = 2; fromValue = 1; keyPath = opacity> 1 opacity
  • 63. 63 <CABasicAnimation:0x610000027340; removedOnCompletion = 0; delegate = <UIViewAnimationState: 0x7fe69e0094e0>; fillMode = both; timingFunction = linear; duration = 2; toValue = 100; fromValue = 0.0; keyPath = uiFractionalProgress> 2 UIPacingAnimationForAnimatorsKey
  • 64. 64 <CABasicAnimation:0x610000027340; removedOnCompletion = 0; delegate = <UIViewAnimationState: 0x7fe69e0094e0>; fillMode = both; timingFunction = linear; duration = 2; toValue = 100; fromValue = 0.0; keyPath = uiFractionalProgress> 2 UIPacingAnimationForAnimatorsKey uiFractionalProgress = 0 -> 100 duration = 2 timingFunction = linear (lldb) po self.presentation()?.value(forKey: "uiFractionalProgress") ▿ Optional<Any>
  • 67. 67 UIPacingAnimationForAnimatorsKey 2 x3 opacity 1 x3 • speed = 0 
 on 4 first • beginTime = -0.398438 on 2 last
  • 68. 68 • By changing fractionComplete you spamming new CABasicAnimation objects
  • 70. 70 • Receipt: • Good Designer 👑 • AfterEffects • Lottie + bodymovin • Done 🎉
  • 71. 71
  • 72. 72
  • 73. 73
  • 74. 74
  • 77. 77
  • 78. 78 animationView = LOTAnimationView(name: "animation") self.view.addSubview(animationView) animationView.play() animationView.animationProgress = CGFloat(sender.value)
  • 79. 79
  • 81. 81 let filepath = Bundle.main.path(forResource: "animation", ofType: "json")! var contents = try! String(contentsOfFile: filepath) contents = contents.replacingOccurrences( of: "[0.6790901,0.178386,0.178386,1]", with: “[0,0.9,0,1]" ) contents = contents.replacingOccurrences( of: "[0.6784314,0.1764706,0.1764706,1]", with: “[0,0.9,0,1]" ) let data = contents.data(using: .utf8)! let json = try! JSONSerialization.jsonObject( with: data, options: [] ) as? [String: Any] animationView = LOTAnimationView(json: json)
  • 82. 82 let filepath = Bundle.main.path(forResource: "animation", ofType: "json")! var contents = try! String(contentsOfFile: filepath) contents = contents.replacingOccurrences( of: "[0.6790901,0.178386,0.178386,1]", with: “[0,0.9,0,1]" ) contents = contents.replacingOccurrences( of: "[0.6784314,0.1764706,0.1764706,1]", with: “[0,0.9,0,1]" ) let data = contents.data(using: .utf8)! let json = try! JSONSerialization.jsonObject( with: data, options: [] ) as? [String: Any] animationView = LOTAnimationView(json: json)
  • 83. 83 let filepath = Bundle.main.path(forResource: "animation", ofType: "json")! var contents = try! String(contentsOfFile: filepath) contents = contents.replacingOccurrences( of: "[0.6790901,0.178386,0.178386,1]", with: “[0,0.9,0,1]" ) contents = contents.replacingOccurrences( of: "[0.6784314,0.1764706,0.1764706,1]", with: “[0,0.9,0,1]" ) let data = contents.data(using: .utf8)! let json = try! JSONSerialization.jsonObject( with: data, options: [] ) as? [String: Any] animationView = LOTAnimationView(json: json) Mutating Phase
  • 84. 84 let filepath = Bundle.main.path(forResource: "animation", ofType: "json")! var contents = try! String(contentsOfFile: filepath) contents = contents.replacingOccurrences( of: "[0.6790901,0.178386,0.178386,1]", with: “[0,0.9,0,1]" ) contents = contents.replacingOccurrences( of: "[0.6784314,0.1764706,0.1764706,1]", with: “[0,0.9,0,1]" ) let data = contents.data(using: .utf8)! let json = try! JSONSerialization.jsonObject( with: data, options: [] ) as? [String: Any] animationView = LOTAnimationView(json: json)
  • 85. 85
  • 86. 86
  • 87. 87 • JSON • Size (in both ways) • Mutatablity • Control • Speed • Progress • Completion • All AfterEffects magic
  • 88. 88 So
  • 89. 89 • Use CAShapeLayers • Combine multiply layers: • Use alpha/scale/mask/… • Use time-based animations
  • 91. 91 Alexander Zimin – UIViewController, откройся!
  • 93. 93 • Avoid time-based animations 🚀 • Implement user interactions (it’s easy 😉) • Create delegate for your custom animations on VCs 🔊 • Check github.com/azimin/AZTransitions 👍