Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Taming Animations

Sash Zats
September 15, 2017

Taming Animations

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

https://vimeo.com/235147763

Sash Zats

September 15, 2017
Tweet

More Decks by Sash Zats

Other Decks in Technology

Transcript

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

    • Software engineers are control freaks • Designers will ❤ you
  2. 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
  3. 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
  4. 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
  5. UIView.animate(with… ! • Not all properties can be animated UIView.animate(withDuration:

    2) { myView.layer.cornerRadius = 20 // iOS 11 ! myShapeView.shapeLayer.path = starPath // " }
  6. 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) }
  7. UIView.animate(with… ! • Not all properties can be animated •

    No designated way to interrupt • Can't be controlled func onSliderChange(_ sender: UISlider) { // ??? }
  8. 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: { })
  9. 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: { }); })
  10. 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:{ }); }); })
  11. 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: { }) }) }); }); })
  12. UIView.animate(with… ! • Fire and forget • Small UI animations

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

    that should never be interrupted • If you are lazy If it's enough
  14. UIViewPropertyAnimator ! • Retains simplicity of block-based API while gives

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

    more control • Add more elements to animation animator.addAnimation { myView.opacity = 0 }
  16. 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)
  17. 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
  18. 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()
  19. 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)
  20. 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 ! }
  21. 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) }
  22. 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.
  23. 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/
  24. 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/
  25. 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/
  26. 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/
  27. 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/
  28. 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")
  29. 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")
  30. 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) }
  31. CoreAnimation ! • With great power comes great complexity •

    Stringly-typed, verbose API • Silently swallows type mismatches • Interaction requires to infer presentation() • Animation jumps: .isRemovedOnCompletion = false
  32. 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")
  33. 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
  34. UIDynamics ! • Works with UIView subclasses let attachment =

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

    a fairly broad range of physical simulations6 6 https://github.com/notjosh/Dynamically
  36. 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
  37. 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
  38. 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
  39. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I:
  40. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I: slow to settle? • It is physics II:
  41. UIDynamics ! • Somewhat limited in what it can do

    Very focused • It is physics I: slow to settle • It is physics II: hard to control
  42. 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/
  43. POP

  44. 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
  45. 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
  46. POP ! • Solves problem similar with UIDynamics, but extensible

    • Make sure your use-case is main thread-affined
  47. 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/
  48. SpriteKit ! • Can't interface with UIKit as much •

    Physics is still very hard to control
  49. 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"
  50. Keyframes & Lottie ! • All batteries included - load

    animation, start playing it • Built on top of CoreAnimation - super performant • Crossplatform
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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