Connect with us

Разработка

Протокол Animatable: укрощение анимаций в SwiftUI

Хотя протокол Animatable изначально не был разработан для решения проблем с анимацией, он стал мощным инструментом для решения сложных проблем с ней.

Опубликовано

/

     
     

В SwiftUI-разработке вы когда-нибудь сталкивались с ситуацией, когда, казалось бы, правильный код анимации не работает так, как ожидалось? Или анимации, которые отлично работают на одних версиях iOS, ведут себя ненормально на других? Эти досадные проблемы с анимацией часто можно решить с помощью мощного, но не слишком заметного инструмента — протокола Animatable.

Протокол Animatable

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

Обычный подход, ориентированный на состояние

Начнем с базового примера анимации — эффекта горизонтального движения, управляемого состоянием:

Реализация на основе Animatable

Того же эффекта можно добиться, реализовав протокол Animatable:

На первый взгляд, реализация на основе Animatable может показаться излишней. Действительно, в большинстве стандартных сценариев анимации мы можем положиться на механизм SwiftUI на основе состояний для создания плавных анимаций. Именно поэтому в повседневной разработке вам редко придется напрямую взаимодействовать с протоколом Animatable.

Использование Animatable для решения аномалий анимации

Хотя система анимации в SwiftUI очень мощная, бывают случаи, когда даже, казалось бы, правильный код может привести к неожиданным аномалиям. В таких случаях на помощь часто приходит Animatable.

Интересно, что во время написания этой статьи я обнаружил, что многие проблемы с анимацией, для устранения которых раньше требовалась Animatable, были решены в Xcode 16. Чтобы лучше проиллюстрировать проблему, я позаимствовал типичный случай с форумов разработчиков Apple.

Демонстрация проблемы

Давайте рассмотрим пример с использованием нового модификатора animation, представленного в iOS 17:

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

Решение Animatable

При анализе выяснилось, что проблема заключается в том, что модификатор offset некорректно обрабатывает состояние анимации внутри замыкания анимации. Давайте воспользуемся Animatable, чтобы реализовать надежную альтернативу:

Теперь просто замените оригинальный offset на наш кастомный модификатор:

Почему стоит выбрать Animatable?

Хотя эту проблему можно решить с помощью явной анимации или возврата к старой версии модификатора анимации, решение на основе Animatable имеет явные преимущества:

  • Сохраняет возможности точного управления нового модификатора animation
  • Избегает потенциальных побочных эффектов от использования withAnimation, таких как запуск анимации в несвязанных представлениях

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

Использование Animatable для создания более точных анимаций

В предыдущей статье «Руководство по SwiftUI geometryGroup(): От теории к практике» я рассказывал о том, как использовать модификатор geometryGroup для улучшения анимационных эффектов. Этот модификатор работает аналогично Animatable — оба преобразуют дискретные состояния в непрерывные потоки данных анимации. Сегодня мы рассмотрим, как использовать Animatable для дальнейшего улучшения анимационных эффектов.

Отдельное спасибо @Chocoford за предоставленный пример кода. Полную реализацию можно посмотреть здесь.

Аномалия расширения View

Рассмотрим пример расширяющегося меню:

Когда вид меню перетаскивается в центр экрана, чтобы развернуться, эффект анимации полностью теряется из-за отсутствия информации об исходном положении. Хотя добавление geometryGroup может заставить анимацию появиться снова:

Однако самые зоркие из вас могли заметить, что направление расширения меню неестественно — оно расширяется слева направо, а не по центру. Это говорит о том, что хотя geometryGroup и обеспечивает анимационную интерполяцию, ее поведением трудно управлять точно.

Решение для оптимизации анимации

Давайте переработаем эту анимацию с помощью Animatable:

Эффект виден сразу:

Это новое решение не только делает анимацию расширения меню более естественной, но и обеспечивает более плавное взаимодействие с пользователем.

Заключение

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

  • Казалось бы, корректный код выдает ненормальную анимацию
  • Анимация ведет себя непоследовательно в разных версиях системы
  • Вам необходимо более точное управление анимацией

Рассмотрите возможность использования Animatable — это может стать ключом к разгадке правильной анимации.

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: