Pro Yearly is on sale from $80 to $50! »

Taming Animations

F4287f42329751d778ac8a869cff3c48?s=47 Sash Zats
September 15, 2017

Taming Animations

Runthrough of various animation technologies available on iOS presented at NSSpain'17

https://vimeo.com/235147763

F4287f42329751d778ac8a869cff3c48?s=128

Sash Zats

September 15, 2017
Tweet

Transcript

  1. Taming Animations

  2. Animations • Breathtaking • Easy to build • Easy to

    control
  3. Animations1 • Breathtaking • Easy to build • Easy to

    control 1 Chose two
  4. Why it's important to control animations? • Sometimes it's not

    • Software engineers are control freaks • Designers will ❤ you
  5. Why to control animations? (srlsy) • Make app feel responsive

  6. Why to control animations? (srlsy) • Make app feel responsive

  7. Why to control animations? (srlsy) • Make app feel responsive

    • Creating immersive UI interactions
  8. Agenda • UIView.animate(with… • UIViewPropertyAnimator • CoreAnimation • UIDynamics •

    POP • SceneKit • Keyframes, Lottie
  9. Legend complexity ! -----> " control ! -----> " flexibility

    ! -----> "
  10. UIView.animate(with…

  11. UIView.animate(with… ! • Easy to use2 UIView.animate(withDuration: 2) { myView.center

    = CGPoint(x: 300, y: 150) } 2 Mandatory reference to "Simple Made Easy" https://www.infoq.com/presentations/Simple- Made-Easy
  12. UIView.animate(with… ! • Easy to use2 • No learning curve

    (maybe .easeIn !) 2 Mandatory reference to "Simple Made Easy" https://www.infoq.com/presentations/Simple- Made-Easy
  13. UIView.animate(with… ! • Easy to use2 • No learning curve

    (maybe .easeIn !) • Powered by CoreAnimation: out of process rendering, won't compete for main thread resources 2 Mandatory reference to "Simple Made Easy" https://www.infoq.com/presentations/Simple- Made-Easy
  14. UIView.animate(with… ! • Not all properties can be animated UIView.animate(withDuration:

    2) { myView.layer.cornerRadius = 20 // iOS 11 ! myShapeView.shapeLayer.path = starPath // " }
  15. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt: func setEnabled(_ enabled: Bool) { UIView.animate(withDuration: 2, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction]) animations: { self.backgroundColor = enabled ? .blue : .grey }, completion: nil) }
  16. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled func onSliderChange(_ sender: UISlider) { // ??? }
  17. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled • Chaining via nested blocks hell UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { })
  18. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled • Chaining via nested blocks hell UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { UIView.animate(withDuration: 3, animation: { self.alpha = 0 }, completion: { }); })
  19. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled • Chaining via nested blocks hell UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { UIView.animate(withDuration: 3, animation: { self.alpha = 0 }, completion: { UIView.animate(withDuration: 3, animations:{ self.fire.setOn(); } completion:{ }); }); })
  20. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled • Chaining via nested blocks hell UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { UIView.animate(withDuration: 3, animation: { self.alpha = 0 }, completion: { UIView.animate(withDuration: 3, animations:{ self.fire.setOn(); } completion:{ UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { UIView.animate(withDuration: 3, animation: { self.backgroundColor = .red }, completion: { }) }) }); }); })
  21. UIView.animate(with… ! • Fire and forget • Small UI animations

    that should never be interrupted • If you are lazy
  22. UIView.animate(with… ! • Fire and forget • Small UI animations

    that should never be interrupted • If you are lazy If it's enough
  23. UIView.animate(with… complexity ! ×----> " control ! ×----> " flexibility

    ! -×---> "
  24. UIViewPropertyAnimator

  25. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

    more control animator = UIViewPropertyAnimator(duration: 2, curve: .easeInOut) { myView.center = CGPoint(x: 300, y: 150) }
  26. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

    more control • Add more elements to animation animator.addAnimation { myView.opacity = 0 }
  27. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

    more control • Add more elements to animation • Poor man chaining animator.addAnimation({ // and then fade out myView.opacity = 0 }, delayFactor: 1)
  28. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

    more control • Add more elements to animation • Poor man chaining • Scrub through animation animator.fractionComplete = slider.value
  29. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

    more control • Add more elements to animation • Poor man chaining • Scrub through animation • Resume paused animation (after scrubbing) animator.startAnimation()
  30. UIViewPropertyAnimator ! • Still relies on properties being exposed to

    UIKit
  31. UIViewPropertyAnimator ! • Still relies on properties being exposed to

    UIKit • Making animation interactive messes following properties setup animator.addAnimation { myView.center = CGPoint(x: 300, y: 150) } animator.pauseAnimation() // this is unlikely to work correctly... myView.center = CGPoint(x: 50, y: 150)
  32. UIViewPropertyAnimator ! • Still relies on properties being exposed to

    UIKit • Making animation interactive messes following properties setup • Making animation interactive kills completion, need to observe isRunning animator.pausesOnCompletion = true animator.addCompletion { _ in // never called ! }
  33. UIViewPropertyAnimator ! • Still relies on properties being exposed to

    UIKit • Making animation interactive messes following properties setup • Making animation interactive kills completion, need to observe isRunning • Deallocating paused animator explodes deinit { animator.stopAnimation(true) }
  34. UIViewPropertyAnimator ! • Still relies on properties being exposed to

    UIKit • Making animation interactive messes following properties setup • Making animation interactive kills completion, need to observe isRunning • Deallocating paused animator explodes • Composition via coordinating array of animators3 3 Wanna project with 5k stars? Build composable UIViewPropertyAnimator subclass.
  35. UIViewPropertyAnimator ! • Great for simple to somewhat complex animations4

    • Good in most of the cases unless you find otherwise • Orchestrating complex animations might be hard 4 Advanced Animations with UIKit https://developer.apple.com/videos/play/wwdc2017/230/
  36. UIViewPropertyAnimator complexity ! ×----> " control ! -×---> " flexibility

    ! -×---> "
  37. CoreAnimation

  38. CoreAnimation ! • Allows to animate everything. Yes even that!

  39. CoreAnimation ! • Allows to animate everything. Yes even that!

    • Out of process rendering - super fast. You can enroll custom callback into same pipeline5 5 https://www.objc.io/issues/12-animations/animating-custom-layer-properties/
  40. CoreAnimation ! • Allows to animate everything. Yes even that!

    • Out of process rendering - super fast. You can enroll custom callback into same pipeline5 • Chaining, delays, relative time… oh my! 5 https://www.objc.io/issues/12-animations/animating-custom-layer-properties/
  41. CoreAnimation ! • Allows to animate everything. Yes even that!

    • Out of process rendering - super fast. You can enroll custom callback into same pipeline5 • Chaining, delays, relative time… oh my! • Scrubbing using speed = 0 & timeOffset 5 https://www.objc.io/issues/12-animations/animating-custom-layer-properties/
  42. CoreAnimation ! • Allows to animate everything. Yes even that!

    • Out of process rendering - super fast. You can enroll custom callback into same pipeline5 • Chaining, delays, relative time… oh my! • Scrubbing using speed = 0 & timeOffset • It is not going away - Apple's behind it 5 https://www.objc.io/issues/12-animations/animating-custom-layer-properties/
  43. CoreAnimation ! • With great power comes great complexity

  44. None
  45. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API let anim = CABasicAnimation(keyPath: "transform.scale.xy") anim.fromValue = 0 anim.toValue = 1 anim.duration = 0.33 anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) anim.delegate = self anim.autoreverses = true anim.repeatCount = 3 anim.fillMode = kCAFillModeBackwards layer.add(anim, forKey: "my-key")
  46. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API • Silently swallows type mismatches let anim = CABasicAnimation(keyPath: "opacity") anim.fromValue = CGAffineTransform(rotationAngle: .pi) anim.toValue = UIColor.whatever // ᕕ( ᐛ )ᕗ layer.add(anim, forKey: "silence-of-the-lambs")
  47. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API • Silently swallows type mismatches • Interaction requires to infer presentation() func point(inside point: CGPoint, with event: UIEvent?) -> Bool { guard let presentation = animatedLayer.presentation() else { return false } let pointInLayer = convert(point, from: self, to: presentation) return presentation.frame.contains(pointInLayer) }
  48. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API • Silently swallows type mismatches • Interaction requires to infer presentation() • Animation jumps: .isRemovedOnCompletion = false
  49. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API • Silently swallows type mismatches • Interaction requires to infer presentation() • Animation jumps .isRemovedOnCompletion = false layer.model().position = layer.presentation()!.position layer.removeAnimation(forKey: "bounce-up")
  50. CoreAnimation ! • For all of you control freaks out

    there • Build-your-own-API edition - if you are writing your framework, chances you will be using CoreAnimation (or CADisplayLink) • Doesn't pretend to be your best friend, but gets job done
  51. CoreAnimation complexity ! ---×-> " control ! ---×-> " flexibility

    ! ---×-> "
  52. UIDynamics

  53. UIDynamics ! • Works with UIView subclasses let attachment =

    UIAttachmentBehavior( item: myView, offsetFromCenter: .zero attachedToAnchor: pan.location(in: view) ) animator.addBehavior(attachment)
  54. UIDynamics ! • Works with UIView subclasses • Allows for

    a fairly broad range of physical simulations6 6 https://github.com/notjosh/Dynamically
  55. UIDynamics ! • Works with UIView subclasses • Allows for

    a fairly broad range of physical simulations6 • Great for breathing a bit of life in your UI 6 https://github.com/notjosh/Dynamically
  56. UIDynamics ! • Works with UIView subclasses • Allows for

    a fairly broad range of physical simulations6 • Great for breathing a bit of life in your UI • Fair amount of control: toggle individual behaviours, live update parameters 6 https://github.com/notjosh/Dynamically
  57. UIDynamics ! • Works with UIView subclasses • Allows for

    a fairly broad range of physical simulations6 • Great for breathing a bit of life in your UI • Fair amount of control: toggle individual behaviours, live update parameters • Notorious for UICollectionView layout 6 https://github.com/notjosh/Dynamically
  58. UIDynamics ! • Somewhat limited in what it can do

  59. UIDynamics ! • Somewhat limited in what it can do

    Very focused
  60. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I:
  61. UIDynamics !

  62. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I: slow to settle? • It is physics II:
  63. UIDynamics !

  64. UIDynamics !

  65. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I: slow to settle • It is physics II: hard to control
  66. UIDynamics ! • Great for small delightful interactions for your

    UI • Even small games in UIDynamics7 • Very specialized • Please make sure it's appropriate - remember Apple Music artists selection UI. 7 http://fancypixel.github.io/blog/2015/06/19/playing-with-uidynamics-in-ios-9/
  67. UIDynamics complexity ! -×---> " control ! -×---> " flexibility

    ! -×---> "
  68. POP

  69. POP ! • Nice API, reasonable defaults, easy to start

    with • Runs on main thread - makes interactive interruptible animations a breeze • Designed for realistic animations: throwing a view takes in account its velocity, putting a finger down makes the view stop etc
  70. POP ! • Runs on main thread - will drop

    frames if you are abusing main thread • If you are building a framework vending animation, don't use POP if you can not guarantee consumers are performant enough
  71. POP ! • Solves problem similar with UIDynamics, but extensible

    • Make sure your use-case is main thread-affined
  72. POP complexity ! -×---> " control ! ---×-> " flexibility

    ! ---×-> "
  73. SpriteKit ! • Apple's answer to Cocos2D - a game

    engine really • Just like GameplayKit can be used to spice up your apps8, SpriteKit can be repurposed, too • Powered by box2d while provides simpler interface • It's to UIDynamics what CoreAnimation to UIView animations • If you haven't heard yet, AR ❤ SpriteKit 8 https://realm.io/news/sash-zats-gameplaykit-beyond-games/
  74. SpriteKit ! • Can't interface with UIKit as much •

    Physics is still very hard to control
  75. SpriteKit ! • Game engine at your disposal. Sky is

    the limit • If you have some time on your hands and want to make your app more delightful (check out PCalc β about screen) • Physics ¯\_(ϑ)_/¯ • When designer comes up to you with "a physical simulation", make sure it is "actual physics"
  76. SpriteKit complexity ! -×---> " control ! ---×-> " flexibility

    ! ---×-> "
  77. Keyframes & Lottie† † http://airbnb.io/lottie/community-showcase.html

  78. Keyframes & Lottie ! • All batteries included - load

    animation, start playing it • Built on top of CoreAnimation - super performant • Crossplatform
  79. Keyframes & Lottie ! • Requires familiarity with After Effect

    • Keyframes can only scrub or replay
  80. Keyframes & Lottie ! • Great for visually reach stories

    (someone has to make them) • Lottie provides more flexibility - you can tweak parameters of the AfterEffects file at runtime
  81. Keyframes & Lottie complexity ! ×----> " control ! ××--->

    " flexibility ! ××---> "
  82. Animations cookbook Use-case Technology Small quick animation, or you just

    feeling lazy UIView.animate(with… Interactive but not overly complicated or reactive UIViewPropertyAnimator Advanced animations, building a framework CoreAnimation
  83. Animations cookbook Use-case Technology Simple physics, snapping, make UI feel

    alive POP or UIDynamics Elaborate interactive animation or complicated physics SceneKit You know AfterEffects, or can hire someone who does Keyframes or Lottie
  84. Conclusions • Be aware of technologies, their ! and "

    - no bad ones* • Mind your project constraints • Write framework if it's missing: iOS haven't always supported AfterEffects animations * okay, fine, there are some
  85. References • Advanced Animations with UIKit, WWDC 2017 • Advances

    in UIKit Animations and Transitions, WWDC 2016 • Advanced Graphics and Animations for iOS Apps, WWDC 2014 • Building Interruptible and Responsive Interactions, WWDC 2014 • Core Animation Essentials, WWDC 2011
  86. References • UIDynamics guide http://samwize.com/ 2016/12/19/uikit-dynamics-guide/ • UICollectionView + UIKit

    Dynamics https:// www.objc.io/issues/5-ios7/collection-views-and- uidynamics/ • Animating Custom Layer Properties https:// www.objc.io/issues/12-animations/animating- custom-layer-properties
  87. Feedback please ! @zats sash@zats.io