Виды анимаций в Android

Часть 1. Базовые анимации

1. Кадр за кадром

В Android до сих пор доступна эта возможность. Всё что нужно сделать это создать xml со ссылками на каждый кадр

• Применение:

Сложные по графике анимации, небольших размеров и подготовленные во внешнем редакторе.

• Достоинства:

Возможность достичь любой сложности эффектов

• Недостатки: 

Большое потребление ресурсов и, как следствие, довольно затратный импорт в приложение с возможностью получить OutOfMemory. Если по каким-то причинам вам нужно показывать большое количество кадров, то придётся писать свою реализацию с постепенной подгрузкой изображений в память.

2. Анимация свойств объекта (aka Property Animator)

Если нам нужно всего-лишь передвинуть что-нибудь на несколько пикселей в сторону или изменить прозрачность, чтобы не плодить миллион очень похожих друг на друга кадров на помощь приходит Animator. Фактически с помощью него можно анимировать любое свойство любых объектов.

Базовый абстрактный класс называется Animator, у него есть несколько наследников, нам важны:

ValueAnimator — позволяет анимировать любое свойство
ObjectAnimator — наследуется от ValueAnimator и имеет упрощённый интерфейс для анимации свойств View.
ViewPropertyAnimator — Предоставляет ещё один удобный интерфейс для анимации View. Не унаследован от Animator и используется в методе View::animate() 

• Применение:

Анимация View объектов и любых их параметров
Анимация любых других параметров

• Достоинства:

Абсолютно универсален

• Недостатки:

В некоторой степени требовательны к ресурсам

3. Анимация View (aka View animation)

До появления Animator в Android были только Animations. Основной недостаток которых был в том что они анимировали только представление вида и никак на самом деле не изменяли его свойства. Поэтому если хочется анимировать перемещение какого-либо элемента, то дополнительно по окончанию анимации нужно изменить ещё его свойства. Такой подход так или иначе не очень удобен, если вам нужна чуть более сложная анимация или нужно отлавливать нажатия в момент анимации.

• Применение:

Там, где API не позволяет использовать Animator.

• Достоинства:

Отсутсвуют

• Недостатки:

Устаревший API, меняет только представление вида.

4. Анимация векторных ресурсов (aka AnimatedVectorDrawable)

Можно относительно малыми силами добиваться сложных и интересных эффектов. Трансформации иконок в Android сделаны именно так.

VectorDrawable состоит из Path и Group элементов. Создание анимации сводится к тому, чтобы прописать движение к этим элементам. 

Начиная с API 25 векторные анимации отрисовываются в RenderThread, поэтому, даже если мы загрузим чем-то наш UI Thread (но мы же никогда так не делаем, да?), анимации всё равно будут проигрываться плавно.

• Применение:

Иконки
Анимационные эффекты

• Достоинства:

Производительность

• Недостатки:

Нет возможности вручную управлять точкой анимации во времени (т.е. фактически отсутствует какой-либо метод, вроде setCurrentTime)

Часть 2. Комплексные анимации

1. Анимация изменений лэйаута (aka animateLayoutChanges)

Всё, что нам нужно сделать это добавить флаг animateLayoutChanges в наш ViewGroup в xml. Теперь, когда мы удаляем или добавляем элемент в наш контейнер, либо изменяем его свойства, они автоматически будут анимированы.

Добавление animateLayoutChanges на самом деле устанавливает LayoutTransition нашей ViewGroup. Но LayoutTransition по умолчанию анимирует только изменение видимости объектов в лэйауте. Поэтому если мы хотим изменять свойства объекта (например ширину и высоту) нужно включить эту опцию отдельно.

• Применение:
Базовая анимация изменений объектов на сцене.
• Достоинства:
Минимальные трудозатраты
• Недостатки:
Слабая кастомизация

2. Transitions framework

Начиная с API 19 в Android появился новый фреймворк позволяющий создавать сложные анимации с участием большого количества элементов и минимумом кода. 

Есть два основных варианта его использования:

1.Использование TransitionManager.beginDelayedTransition(ViewGroup)
Чтобы создать анимацию необходимо перед внесением изменений в наши View вызвать TransitionManager.beginDelayedTransition(ViewGroup) и передать в него ViewGroup, который мы хотим анимировать. Фрэймворк запомнит состояние View и запустит анимацию на следующем кадре.

2. Создание сцен
Создание анимации в этом случае сводится к созданию двух похожих xml, отвечающих за начальное и конечное состояние ваших анимаций. Соответственно, id объектов в xml должны совпадать, чтобы дать фреймворку возможность найти соответствие (На самом деле beginDelayedTransition тоже создаёт сцены, одну в момент вызова, а вторую на следующем кадре. После чего запускает анимацию между ними).

• Применение:
— Анимация большого количества объектов

• Достоинства:
— Минимальные трудозатраты
— Доступная кастомизация

Часть 3. «Низкоуровневые» анимации

1. Рисование на канвасе View

Первый способ который мы рассмотрим это рисование в методе onDraw нашего объекта View. Реализуется данный способ просто, достаточно переопределить onDraw и в конце вызвать postInvalidateOnAnimation().

Применение:

  • Случаи в которых легче нарисовать анимацию программно

Достоинства:

  • Можно создавать анимации зависящие абсолютно от любых параметров
  • Нет лишних затрат на объекты View

Недостатки:

  • Расчёты анимации и отрисовка происходят в UI thread

2. Рисование на канвасе SurfaceView

Android позволяет отвязаться от основного цикла(main loop) отрисовки с помощью компонента SurfaceView. А раз мы больше не привязаны к основному циклу, то нам придётся держать свой поток для расчётов и отрисовки. SurfaceView предоставляет коллбэки в которых мы можем запустить и остановить наш поток. В потоке по окончанию расчётов мы будем отрисовывать нашу анимацию.

Применение:

  • Случаи в которых легче нарисовать анимацию программно
  • Игры

Достоинства:

  • Можно создавать анимации зависящие абсолютно от любых параметров
  • Нет лишних затрат на объекты View

Недостатки:

  • Сложность имплементации

3. OpenGL

Точно также, как и на канвасе, мы можем рисовать используя OpenGL API. Если вы задумали что-либо сложнее чем куб на картинке, то стоит посмотреть в сторону какого-либо движка, например libgdx. К сожалению, даже базовый пример займёт здесь довольно много места, поэтому ограничимся только этим кратким превью. 

Применение:

  • Сложные эффекты
  • 3D
  • Игры

Достоинства:

  • Высокая производительность и управление памятью, шейдеры

Недостатки:

  • Сложность имплементации