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

ADDC 2017 - John Sundell: Creating great animat...

ADDC 2017 - John Sundell: Creating great animations on iOS

Animations are a huge part of modern application design - and on iOS we have quite a number of tools at our disposal to create great ones to delight & inform our users. Durning this talk, John will go through several animation techniques and talk about how they can be used to create a smooth workflow for both developers & designers - and resulting in a great user experience.

More about the talk, authors & slides: https://addconf.com/talks/7/
Read about the conference: https://addconf.com

More Decks by ADDC - App Design & Development Conference

Other Decks in Technology

Transcript

  1. Jump let jumpAction = SKAction.sequence([ .moveBy(x: 0, y: 3, duration:

    0.1), .moveBy(x: 0, y: -3, duration: 0.1) ]) let carAction = SKAction.sequence([ jumpAction .wait(forDuration: 2) ])
  2. Jump let jumpAction = SKAction.sequence([ .moveBy(x: 0, y: 3, duration:

    0.1), .moveBy(x: 0, y: -3, duration: 0.1) ]) let carAction = SKAction.sequence([ jumpAction .wait(forDuration: 2) ]) carNode.run(.repeatForever(carAction))
  3. Jump let jumpAction = SKAction.sequence([ .moveBy(x: 0, y: 3, duration:

    0.1), .moveBy(x: 0, y: -3, duration: 0.1) ]) let wheelAction = SKAction.sequence([ .rotate(byAngle: .pi * 2, duration: 1.5) jumpAction ]) wheelNode.run(.repeatForever(wheelAction)) Rotate & jump let carAction = SKAction.sequence([ jumpAction .wait(forDuration: 2) ]) carNode.run(.repeatForever(carAction))
  4. Jump let jumpAction = SKAction.sequence([ .moveBy(x: 0, y: 3, duration:

    0.1), .moveBy(x: 0, y: -3, duration: 0.1) ]) let wheelAction = SKAction.sequence([ .rotate(byAngle: .pi * 2, duration: 1.5) jumpAction ]) wheelNode.run(.repeatForever(wheelAction)) Rotate & jump let carAction = SKAction.sequence([ jumpAction .wait(forDuration: 2) ]) carNode.run(.repeatForever(carAction))
  5. ) Great for complex stand-alone scenes - Easy to compose

    actions to build animations . Create hierarchies matching the asset structure ♻ Actions can be reused and their parameters can be easily tweaked SpriteKit
  6. button.alpha = 0 UIView.animate(withDuration: 0.3, animations: { button.alpha = 1

    }, completion: { _ in UIView.animate(withDuration: 0.3) { button.frame.size = CGSize(width: 200, height: 200) } })
  7. struct Animation { var duration: TimeInterval var closure: (UIView) ->

    Void } extension Animation { } static func fadeIn(duration: TimeInterval) -> Animation { return Animation(duration: duration, closure: { $0.alpha = 1 }) } static func scale(to size: CGSize, duration: TimeInterval) -> Animation { return Animation(duration: duration, closure: { $0.frame.size = size }) }
  8. extension UIView { func animate(_ animations: [Animation]) { guard !animations.isEmpty

    else { return } var animations = animations let animation = animations.removeFirst() UIView.animate(withDuration: animation.duration, animations: { animation.closure(self) }, completion: { _ in self.animate(animations) }) } }
  9. extension UIView { func animate(_ animations: [Animation]) { guard !animations.isEmpty

    else { return } var animations = animations let animation = animations.removeFirst() UIView.animate(withDuration: animation.duration, animations: { animation.closure(self) }, completion: { _ in self.animate(animations) }) } } Exit condition
  10. extension UIView { func animate(_ animations: [Animation]) { guard !animations.isEmpty

    else { return } var animations = animations let animation = animations.removeFirst() UIView.animate(withDuration: animation.duration, animations: { animation.closure(self) }, completion: { _ in self.animate(animations) }) } } Exit condition Take out the next animation
  11. extension UIView { func animate(_ animations: [Animation]) { guard !animations.isEmpty

    else { return } var animations = animations let animation = animations.removeFirst() UIView.animate(withDuration: animation.duration, animations: { animation.closure(self) }, completion: { _ in self.animate(animations) }) } } Exit condition Take out the next animation Perform the animation
  12. extension UIView { func animate(_ animations: [Animation]) { guard !animations.isEmpty

    else { return } var animations = animations let animation = animations.removeFirst() UIView.animate(withDuration: animation.duration, animations: { animation.closure(self) }, completion: { _ in self.animate(animations) }) } } Exit condition Take out the next animation Perform the animation Recursively call the method
  13. burrito.animate([ .scale(to: burrito.frame.size * 1.5, duration: 0.3), .move(to: basket.center, duration:

    0.3) ]) burrito.animate(inParallel: [ .scale(to: burrito.frame.size * 0.5, duration: 0.3), .fadeOut(duration: 0.3) ]) iHungry 0 1 2 3 4 5 6 7 8 9 : ; < = >
  14. burrito.animate([ .scale(to: burrito.frame.size * 1.5, duration: 0.3), .move(to: basket.center, duration:

    0.3) ]) burrito.animate(inParallel: [ .scale(to: burrito.frame.size * 0.5, duration: 0.3), .fadeOut(duration: 0.3) ]) basket.animate([ .scale(to: basket.frame.size * 1.5, duration: 0.3), .scale(to: basket.frame.size, duration: 0.3) ]) iHungry 0 1 2 3 4 5 6 7 8 9 : ; < = >
  15. burrito.animate([ .scale(to: burrito.frame.size * 1.5, duration: 0.3), .move(to: basket.center, duration:

    0.3) ]) burrito.animate(inParallel: [ .scale(to: burrito.frame.size * 0.5, duration: 0.3), .fadeOut(duration: 0.3) ]) basket.animate([ .scale(to: basket.frame.size * 1.5, duration: 0.3), .scale(to: basket.frame.size, duration: 0.3) ]) badge.animate(.fadeIn(duration: 0.3)) iHungry 0 1 2 3 4 5 6 7 8 9 : ; < = > 1
  16. %