Лучшая анимация iOS с CATransaction

Core Animation, платформа Cocoa, отвечающая за большинство анимаций iOS и macOS, представляет собой сложную систему с множеством скрытых и менее известных функций.

Core Animation обрабатывает ваши анимации за кулисами, и, зная немного больше о том, как это работает, мы можем в полной мере воспользоваться этим и создать хорошо настроенные анимации.

Анимации просты. За исключением случаев, когда они не.
BetterAnimations.playground

Анимации - это лучший способ отобразить изменения для пользователя. UIKit от Apple (или AppKit для macOS) превращает анимацию в бриз. Вероятно, вы использовали UIKit для большинства ваших анимационных встреч, и код, вероятно, выглядит примерно так:

Это чистый и простой в использовании. Высокоуровневые UIKit / AppKit-фреймворки (которые находятся выше Core Animation) отлично справляются с задачей облегчения анимации. Тем не менее, есть некоторые подводные камни, когда вы хотите более сложные движения.

Пример анимации

Учтите это: у вас есть UIButton, потомок UIView, и вы хотите сделать его круговым, и при касании он изменит размер вида.

Звучит прямо вперед. Мы можем анимировать styledButton.layer.cornerRadius и установить его на половину ширины при изменении нашего кадра. Но подождите ... есть проблема. UIView.animate (...) будет обрабатывать только анимацию свойств вида, а не анимацию свойств слоя. Если мы попытались изменить кадр styledButton и cornerRadius для styledButton в анимационном блоке ниже, мы получим непреднамеренный эффект:

Результат сегмента кода

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

Inside Core Animation

Экземпляры UIView (а также экземпляры NSView на основе слоя) имеют свойство CALayer, которое называется layer, с которым работают анимации. Представление делегирует рендеринг их слоев в Core Animation. Однако, когда анимации добавляются в слой, свойства слоя не изменяются напрямую.

Базовая анимация содержит две параллельные иерархии дерева: дерево уровня модели и дерево уровня представления. Это можно увидеть в свойствах presentationLayer и modelLayer в CALayer. Именно презентационный слой отвечает за отображение любых изменений во время анимации. Если вы должны анимировать свойство borderWidth слоя и наблюдать значение во время анимации, значение borderWidth изменится только в дереве слоя представления во время анимации.

С помощью CABasicAnimation мы можем анимировать свойства слоя. Но не позволяйте слову «Basic» обескураживать вас - это один из самых мощных инструментов анимации для тонкой настройки вашей анимации.

Практическое примечание. Хорошей практикой анимации является установка анимируемого значения на новое значение перед добавлением анимации. Обычно для свойства fillMode установлено значение kCAFillModeForwards, а для свойства isRemovedOnCompletion установлено значение false. Однако то, что это делает, по сути «приостанавливает» наш уровень представления в конце анимации. Рекомендуется синхронизировать слои модели и представления, и, установив значение перед добавлением анимации, мы можем сделать это.

CATransaction - сгладить анимацию

Хорошо. Вернуться к нашему примеру UIButton из ранее. Мы хотим анимировать свойство layerRadius слоя и одновременно анимировать свойство frame представления и гарантировать, что они остаются идеально синхронизированными для лучшей анимации.

CATransaction на помощь!

CATransaction часто игнорируется большинством разработчиков. Задача CATransaction - группировать несколько связанных с анимацией действий вместе. Это гарантирует, что требуемые изменения анимации фиксируются в Core Animation одновременно.

Здесь мы начинаем транзакцию и можем изменить любые свойства, включенные в Core Animation, которые будут анимированы вместе после фиксации.

Собираем все вместе

Поэтому мы хотим анимировать слой и просматривать свойства одновременно. Это идеальное использование для CATransaction. Мы даже можем использовать наш существующий код UIView.animate () и CABasicAnimation!

Результирующая анимация

В этом примере я использую анимацию UIView и CABasicAnimation для выполнения этой задачи. Все, что координируется CATransaction, будет передано другим анимациям. Например, функция setAnimationDuration (dur: CFTimeInterval) будет применяться к CABasicAnimation, поэтому нам не нужно указывать какую-либо продолжительность. Тем не менее, поскольку UIView.animate () заставляет нас указывать длительность, мы можем просто установить длительность на ту же, что указана в setAnimationDuration CATransaction.

Пользовательские анимации ключевых кадров

Еще одно полезное использование - это использование функции хронирования CATransaction для определения собственной кривой анимации Безье. Если вы поместите свой UIView.animate () в CATransaction, вы сможете получить точный контроль над кривой анимации:

Окончательная анимация с функцией синхронизации

Резюме

CATransaction является мощным координатором для ваших анимаций и сэкономит вам массу времени, предоставляя вам точный контроль над вашими анимациями. Кроме того, здесь не куча вложенных блоков, что всегда является удобочитаемостью.

Полный игровой проект Swift 3 с использованием CATransaction вместе с UIKit и CABasicAnimation можно найти здесь:

Спасибо за чтение! Если у вас есть вопросы или предложения - не стесняйтесь обращаться!