iOS 10: новое в создании анимаций

в 8:58, , рубрики: ios development, redmadrobot, swift, WWDC 2016, Блог компании REDMADROBOT, разработка мобильных приложений, разработка под iOS

iOS 10: новое в создании анимаций - 1

Не так давно на WWDC 2016 был анонсирован обновленный интерфейс работы с интерактивными анимациями в iOS 10: теперь у разработчиков появился гибкий инструмент их создания, управления и модификации. В этой статье речь пойдет о том, какие произошли изменения и что из себя представляет новое API.

Центральным классом нового API является UIViewPropertyAnimator, предоставляющий свой функционал на основе двух протоколов UIViewAnimating и UIViewImplicitlyAnimating, которые будут рассмотрены ниже.

UIViewPropertyAnimator

С помощью данного класса можно:

  • создавать интерактивные анимации (их можно останавливать, ставить на паузу, прерывать, обрабатывать касания пользователя);
  • модифицировать уже запущенные;
  • перематывать текущую анимацию на любой момент;
  • проигрывать в обратном порядке;
  • настраивать timing functions.

Timing functions

Под timing functions (или easing functions) понимаются функции скорости анимации, которые влияют на темп изменения того или иного анимируемого свойства. Сейчас поддерживается четыре типа: easeInOut, easeIn, easeOut, linear.

Пример использования:

        // Скорость анимации
        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()

Может показаться, что такая реализация более многословна по сравнению со старым API, зато теперь есть аниматор, который можно реиспользовать/изменять/сохранять и наслаждаться остальными преимуществами наличия цельного объекта.

Также Apple предоставляет новые протоколы:

iOS 10: новое в создании анимаций - 2

UIViewAnimating

Этот протокол отвечает за основные действия, которые мы можем выполнить с аниматором: запуск, пауза, остановка, перемотка, получение текущего состояния и позиции анимации. Больше информации можно получить в документации. Остановимся на паре методов и свойств чуть подробнее:

Перемотка анимации (scrubbing)

var fractionComplete: CGFloat { get set }

animator.fractionComplete = fraction

С помощью такого свойства можно поэтапно продвигаться по анимации вперед/назад, получая ее состояние в выбранный момент времени. Благодаря такой возможности пользователь может взаимодействовать с интерфейсом как с чем-то живым и интерактивным.

Пример

Иконка робота вращается и увеличивается, двигаясь по горизонтали вправо. Изначально анимация на паузе. На иконку добавлены UIPanGestureRecognizer (при вызове выставляет fraction для анимации) и UITapGestureRecognizer (при тапе анимация проигрывается).

Сначала тянем иконку вправо и вручную проматываем анимацию (UIPanGestureRecognizer). Затем тапаем по иконке и смотрим на анимацию, которая проигрывается сама (UITapGestureRecognizer).

iOS 10: новое в создании анимаций - 3

Завершение анимации

func finishAnimation(at: UIViewAnimatingPosition)

Входной параметр at показывает, в какой позиции полностью завершится анимация.
Варианты значений enum UIViewAnimatingPosition:

  • start;
  • end;
  • current (текущая позиция — любая точка цикла анимации).

Параметр позиции может оказаться очень полезным, когда потребуется закончить анимацию в нестандартном состоянии. Например, в середине цикла или на последнем кадре.

(Временная) остановка анимации

func stopAnimation(_ withoutFinishing: Bool) 

Параметр withoutFinishing позволяет либо остановить анимацию полностью (как при использовании finishAnimation), либо перевести в состояние stopped, из которого анимацию можно продолжить с текущего места.

Состояние анимации

  • inactive
    Начальное состояние — каждый новый созданный объект-аниматор начинает с него. После завершения анимации (finishAnimation) он возвращается к этому же состоянию.
  • active
    Аниматор переходит в такое состояние после вызовов startAnimation() или pauseAnimation().
  • stopped
    Состояние аниматора после вызова stopAnimation, где withoutFinishing == false.

Наглядное изображение изменения состояния:

iOS 10: новое в создании анимаций - 4

И еще несколько интересных свойств UIViewAnimating:

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


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




При значении по умолчанию анимируемый объект будет получать все касания пользователя. 
Если выставить isManualHitTestingEnabled = true, то все тачи будет получать не объект в своем текущем состоянии (presentation layer), а его модельный слой (model layer), то есть в финальном состоянии, как будто анимация уже кончилась.

Пример

Для этой анимации выставлен isManualHitTestingEnabled = true. На иконку добавлен UITapGestureRecognizer (при тапе текст лейбла внизу изменится на Received touch). Как видно, иконка в движении не получает касания пользователя, но если тапнуть на предполагаемое место окончания анимации (самая правая часть поля), селектор сработает, как будто иконка находится именно там.
iOS 10: новое в создании анимаций - 5

UIViewImplicitlyAnimating

Этот протокол наследуется от предыдущего (UIViewAnimating) и предоставляет важную часть функционала: добавление анимаций через блок и создание completion block.

Одна из новых возможностей — это продолжение анимации после паузы или остановки, причем с изменением timing function.

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

Это может пригодиться, если нужно изменить темп анимации после взаимодействия с пользователем (остановки или паузы анимации).

UITimingCurveProvider

Используется при создании объекта UIViewPropertyAnimator для установки timing function через UISpringTimingParameters или UICubicTimingParameters.

iOS 10: новое в создании анимаций - 6

UICubicTimingParameters

Сейчас UIKIt дает нам только четыре старые добрые функции скорости (easeInOut, easeIn, easeOut, linear).
Но в новом API появился простор для фантазии дизайнеров — возможность создавать свои timing functions по двум контрольным точкам:

iOS 10: новое в создании анимаций - 7

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 позволяют получить упругое поведение.

iOS 10: новое в создании анимаций - 8

Здесь интересным моментом является то, что скорость теперь вектор, а не скаляр. Раньше скорость была направлена вдоль линии в отличие от нового API, где расчет идет по двум осям, а значит, анимация выглядит более натурально.

А еще Apple открыли для использования spring equation, то есть теперь можно устанавливать любые коэффициенты и настройки для UISpringTimingParameters, но надо учитывать, что в этом случае длительность игнорируется и высчитывается соответственно параметрам:

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

Заключение

После просмотра лекции и нескольких примеров кода остается общее впечатление, что добавилось разнообразие и возможности для экспериментов с timing functions и модификацией анимаций, а API стало более многословным, но гибким. Будем надеяться, разработчикам теперь станет еще проще и приятнее добавлять интерактив в свои приложения!
Подробнее познакомиться с примерами можно в лекции Advances in UIKit Animations and Transitions.

Автор: REDMADROBOT

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js