iOS 10: new in creating animations

  • Tutorial


Not so long ago, at WWDC 2016, an updated interface for working with interactive animations in iOS 10 was announced: now developers have a flexible tool for creating, managing and modifying them. This article will discuss what changes have occurred and what the new API is.

The central class of the new API is UIViewPropertyAnimator, which provides its functionality based on the two protocols UIViewAnimating and UIViewImplicitlyAnimating, which will be discussed below.

UIViewPropertyAnimator


Using this class you can:

  • create interactive animations (they can be stopped, paused, interrupted, processed by the user's touch);
  • modify already running ones;
  • rewind the current animation at any time;
  • play in reverse order;
  • set up timing functions.

Timing functions
Timing functions (or easing functions) are understood as animation speed functions that affect the rate of change of one or another animated property. Four types are currently supported: easeInOut, easeIn, easeOut, linear.

Usage example:

        // Скорость анимации
        let parameters = UICubicTimingParameters(animationCurve: .easeIn)
        // Конфигурирование аниматора с учетом длительности и скорости
        let animator = UIViewPropertyAnimator(duration: 5.0, timingParameters: parameters)
        // Набор анимаций (как во всем знакомом UIView.animate(withDuration:, animations:))
        animator.addAnimations {
            view.center = CGPoint(x: 150, y: 200)
            view.transform = CGAffineTransform(rotationAngle: CGFloat(M_PI_2))
            view.backgroundColor = UIColor.red()
        }
        // Completion block
        animator.addCompletion { _ in
            view.backgroundColor = UIColor.orange()
        }
        // Запуск проигрывания анимации
        animator.startAnimation()


It may seem that such an implementation is more verbose compared to the old API, but now there is an animator that you can reuse / modify / save and enjoy the rest of the benefits of having a solid object.

Apple also provides new protocols:



UIViewAnimating


This protocol is responsible for the main actions that we can perform with the animator: start, pause, stop, rewind, getting the current state and position of the animation. More information is available in the documentation . Let us dwell on a couple of methods and properties in more detail:

Rewind animation (scrubbing)

var fractionComplete: CGFloat { get set }
animator.fractionComplete = fraction

Using this property, you can gradually move forward / backward through the animation, getting its state at the selected point in time. Thanks to this feature, the user can interact with the interface as something alive and interactive.

Example
The robot icon rotates and increases, moving horizontally to the right. Initially paused animation. UIPanGestureRecognizer (sets a fraction for the animation when called) and UITapGestureRecognizer (the animation plays when the tap is added) are added to the icon.

First, drag the icon to the right and manually scroll the animation (UIPanGestureRecognizer). Then tap on the icon and look at the animation that plays itself (UITapGestureRecognizer).




Animation completion

func finishAnimation(at: UIViewAnimatingPosition)

The input parameter at indicates at which position the animation will complete.
Options for enum UIViewAnimatingPosition values :

  • start;
  • end;
  • current (current position is any point in the animation loop).

The position parameter can be very useful when you need to finish the animation in a non-standard state. For example, in the middle of a loop or in the last frame.

(Temporary) stop animation

func stopAnimation(_ withoutFinishing: Bool) 

The withoutFinishing parameter allows either to stop the animation completely (as when using finishAnimation), or switch it to the stopped state, from which the animation can be continued from the current place.

Animation Status

  • inactive
    Initial state - each newly created animator starts with it. After the animation (finishAnimation) is completed, it returns to the same state.
  • active The
    animator transitions to this state after calls to startAnimation () or pauseAnimation ().
  • stopped The
    state of the animator after calling stopAnimation, where withoutFinishing == false.


Visualization of a state change:



And some more interesting properties of UIViewAnimating:

// Можно ли анимацию ставить на паузу или останавливать
var isInterruptible: Bool 


// Способ обработки тачей (по умолчанию false)
var isManualHitTestingEnabled: Bool 

With the default value, the animated object will receive all user touches. If you set isManualHitTestingEnabled = true, then all the tachi will not receive the object in its current state (presentation layer), but its model layer (model layer), that is, in the final state, as if the animation has already ended.

Example
For this animation, isManualHitTestingEnabled = true. UITapGestureRecognizer has been added to the icon (with a tap, the label text at the bottom will change to Received touch). As you can see, the icon in motion does not get the user's touch, but if you tap on the supposed end of the animation (the rightmost part of the field), the selector will work as if the icon is there.



UIViewImplicitlyAnimating


This protocol inherits from the previous one (UIViewAnimating) and provides an important part of the functionality: adding animations through a block and creating a completion block.

One of the new features is the continuation of the animation after a pause or stop, and with a change in the timing function.

 let newParameters = UICubicTimingParameters(animationCurve: .easeOut)
 animator.continueAnimation(withTimingParameters: newParameters, durationFactor: 2.0)

This can come in handy if you need to change the pace of the animation after interacting with the user (stopping or pausing the animation).

UITimingCurveProvider


Used when creating a UIViewPropertyAnimator object to set the timing function via UISpringTimingParameters or UICubicTimingParameters.



UICubicTimingParameters

Right now, UIKIt gives us only four good old speed functions (easeInOut, easeIn, easeOut, linear).
But in the new API there was scope for the imagination of designers - the ability to create your timing functions at two control points:



let controlPoint1 = CGPoint(x: 0.2, y: 0.1)
let controlPoint2 = CGPoint(x: 0.8, y: 0.8)
let parameters = UICubicTimingParameters(controlPoint1: controlPoint1, controlPoint2: controlPoint2)
animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: parameters)


UISpringTimingParameters

UISpringTimingParameters allow you to get resilient behavior.


An interesting point here is that speed is now a vector, not a scalar. Previously, the speed was directed along the line, unlike the new API, where the calculation goes along two axes, which means that the animation looks more natural.

And Apple opened the spring equation for use, that is, now you can set any coefficients and settings for UISpringTimingParameters, but keep in mind that in this case the duration is ignored and calculated according to the parameters:

// Spring equation
init(mass: CGFloat, stiffness: CGFloat, damping: CGFloat, initialVelocity velocity: CGVector)


Conclusion


After viewing the lecture and a few code examples, the general impression is that diversity and opportunities for experimenting with timing functions and modifying animations have been added, and the API has become more verbose but flexible. Let's hope the developers will now find it even easier and more pleasant to add interactive to their applications!
You can learn more about examples in the lecture Advances in UIKit Animations and Transitions .


Also popular now: