По-добри iOS анимации с CATransaction

Core Animation, рамката на Cocoa, отговорна за повечето анимации на iOS и macOS, е сложна система с много скрити и по-малко известни функционалности.

Core Animation борави с вашите анимации зад кулисите и като знаем малко повече как тя работи, можем да се възползваме максимално от нея и да създаваме прецизирани анимации.

Анимациите са лесни. Освен когато не са.
BetterAnimations.playground

Анимациите са най-добрият начин за показване на промяна на потребител. UIKit на Apple (или AppKit за macOS) на Apple прескача в анимации. Вероятно сте използвали UIKit за повечето си срещи с анимация и кодът вероятно изглежда така:

Той е чист и лесен за използване. Рамките UIKit / AppKit от по-високо ниво (които седят над Core Animation) вършат чудесна работа за улесняване на анимациите. Има обаче някои клопки, когато искате по-сложни движения.

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

Помислете за това: имате UIButton, потомък на UIView, и искате да го направите с кръгъл изглед и при натискане ще промени размера на изгледа.

Звучи направо напред. Можем да анимираме styledButton.layer.cornerRadius и да го настроим на половината от ширината, докато нашата рамка се променя. Но почакайте ... има проблем. UIView.animate (...) ще обработва само анимации на собствеността на изгледа, а не анимации на свойствата на слоя. Ако се опитаме да променим рамката на styledButton и ъгълаRadius of styledButton в анимационния блок по-долу, получаваме непредвиден ефект:

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

Рамката анимира правилно, но cornerRadius скача директно до новата си стойност, без да анимира. По-късно ще говорим за CATransaction и как ще реши този проблем. Но първо, добре е да знаем какво се случва под капака на нашите анимации и защо това се случва.

Вътрешна анимация

Екземплярите на UIView (както и подкрепените със слой екземпляри NSView) имат свойство CALayer, наречено слой, върху който работят анимациите. Изгледът делегира изобразяването на техните слоеве на Core Animation. Когато обаче към слоя се добавят анимации, неговите свойства не се променят директно.

Core Animation съдържа две паралелни йерархии на дърво: дърво на моделен слой и дърво на презентационния слой. Те могат да се видят в CALayer’s presenLayer и свойстваLayer свойства. Именно презентационният слой е отговорен за показването на всяка промяна по време на анимация. Ако трябваше да анимирате свойството borderWidth на слой и да наблюдавате стойността по време на анимацията, стойността borderWidth ще се промени само в дървото на презентационния слой по време на анимацията.

Чрез CABasicAnimation можем да анимираме свойствата на слоя. Но не позволявайте думата „Basic“ да ви обезкуражи - това е един от най-мощните анимационни инструменти за фино настройване на вашите анимации.

Практическа бележка: Добра практика за анимация е да зададете стойността, която анимирате, на новата стойност, преди да добавите анимацията. Обичайно е да видите свойството fillMode, зададено на kCAFillModeForwards, а isRemovedOnCompletion да е невярно. Това обаче прави по същество „пауза“ на нашия презентационен слой в края на анимацията. Добра практика е да поддържаме синхронизирането на модела и презентационните слоеве и като зададем стойността преди да добавим анимацията, можем да направим точно това.

CATransaction - за изглаждане на вашите анимации

Добре. Обратно към нашия пример на UIButton от по-рано. Искаме да анимираме свойството cornerRadius на слоя и да анимираме собствеността на рамката на изгледа едновременно и да гарантираме, че те остават перфектно синхронизирани за най-добрата анимация.

CATактивност при спасяването!

CATransaction е често пренебрегван клас от повечето разработчици. Задачата на CATransaction е да групира няколко действия, свързани с анимация заедно. Той гарантира, че желаните промени в анимацията са ангажирани едновременно с Core Animation.

Тук започваме транзакция и можем да променим всички свойства с активирана Core Animation, които ще бъдат анимирани едно след друго веднъж извършени.

Поставяме всичко заедно

Така че ние искаме да анимираме слой и да преглеждаме свойствата едновременно. Това е перфектна употреба за CATransaction. Можем дори да използваме съществуващите ни UIView.animate () и CABasicAnimation код!

Резултатна анимация

В този пример използвам едновременно UIView анимация и CABasicAnimation, за да завърша тази задача. Всичко, координирано от CATransaction, ще бъде прехвърлено към други анимации. Например функцията setAnimationDuration (dur: CFTimeInterval) ще се прилага към CABasicAnimation, така че не е необходимо да определяме продължителност. Въпреки това, тъй като UIView.animate () ни кара да определим продължителността, ние можем просто да зададем продължителността на същата, посочена в CATransaction’s setAnimationDuration.

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

Друго прецизно използване е да използвате времевата функция на CATransaction, за да определите вашата собствена крива на анимация на Bezier. Ако обвиете UIView.animate () вътре в CATransaction, можете да получите точен контрол над вашата анимационна крива:

Окончателна анимация с функция на времето

резюме

CATransaction е мощен координатор за вашите анимации и ще ви спести тонове време, като същевременно ви дава прецизен контрол върху вашите анимации. Плюс това не е куп вложени блокове - което винаги е плюс за четене.

Пълният проект за детска площадка Swift 3, използващ CATransaction, заедно с UIKit и CABasicAnimation, можете да намерите тук:

Благодаря за четенето! Ако имате въпроси или предложения - не се колебайте да се свържете!