Android анимации. Часть 3. SVG, vector и управление анимацией
В прошлой статье мы увидели зачем нам Animator и как использовать анимации при смене состояний View. В этой статье мы посмотрим, как использовать анимации векторных картинок.
Простая анимация. Animator - первая статья
Простая анимация. State View - вторая статья
Vector анимация. Стандартные решения – третья статья
VectorDrawable анимация. Управление анимацией. Хардкор – четвертая статья
Я считаю, что это самые интересные анимации. При помощи небольших усилий мы можем добиться интересных эффектов. Изменения различных иконок, тот же hamburger превращающийся в стрелочку назад, реализованы именно так.
VectorDrawable состоит из Group и Path элементов. Анимацию мы создадим описав, как должны изменяться эти элементы.
Давайте разберем как превратить значок play в значок pause.
Для этого нам нужно нарисовать svg. Сделать это можно используя различные программы. Я использовал онлайн сервис – editor.method.ac. Чтобы красиво анимировать play в pause нам нужно разбить его на две части – верхний треугольник и нижний. Рисуем, сохраняем в svg и добавляем в наш проект при помощи Vector Assets.
Теперь у нас есть ic_play.xml:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportHeight="128"
android:viewportWidth="128">
<group
android:name="group"
android:pivotX="64"
android:pivotY="64">
<path
android:name="pause1"
android:fillColor="#000"
android:pathData="M 44 32 L 44 64 L 100 64 L 100 64 Z"
android:strokeColor="#000"
android:strokeWidth="1" />
<path
android:name="pause2"
android:fillColor="#000"
android:pathData="M 44 96 L 44 64 L 100 64 L 100 64 Z"
android:strokeColor="#000"
android:strokeWidth="1" />
</group>
</vector>
Обратите внимание, что мы задали pivotX и pivotY. Этим мы указали середину картинки для правильного поворота нашего изображения.
Дальше нужно создать несколько xml в package res/animator.
top_play_to_pause.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M 44 32 L 44 64 L 100 64 L 100 64 Z"
android:valueTo="M 32 40 L 32 56 L 96 56 L 96 40 Z"
android:valueType="pathType" />
bottom_play_to_pause.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M 44 96 L 44 64 L 100 64 L 100 64 Z"
android:valueTo="M 32 88 L 32 72 L 96 72 L 96 88 Z"
android:valueType="pathType" />
Обратите внимание, что мы здесь описали. Мы сказали, что один path (valueFrom скопирован из ic_play.xm) должен превратиться в другой. Где нам взять этот самый другой? Опять рисуем его в онлайн редакторе и добавляем в проект, чтобы получить VectorDrawable path который сможем вставить в valueTo. Как будет выглядеть наша трансформация? Мы можем очень удобно проверять это при помощи сервиса shapeshifter.design (если необходима будет помощь, пишите комментарии). Очень удобно в нем то, что он нам может выдать готовый xml, который останется лишь вставить в наш проект.
Также нам понадобится еще один xml в package res/animator - rotate_90.xml:
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="90"
android:valueType="floatType" />
Теперь нам нужно соединить это все воедино. Сделаем для этого xml в res/drawable - ic_play_to_pause.xml:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_play">
<target
android:name="group"
android:animation="@animator/rotate_90" />
<target
android:name="pause1"
android:animation="@animator/top_play_to_pause" />
<target
android:name="pause2"
android:animation="@animator/bottom_play_to_pause" />
</animated-vector>
Студия может ругаться на то, что animated-vector можно использовать только в API>21, но не обращайте на это внимание :) Что мы сделали здесь? Мы связали разные objectAnimator с разными частями нашего ic_play.xml по android:name.
Что дальше?
Идем в activity_main.xml и добавляем туда наш значок:
<android.support.v7.widget.AppCompatImageView
…
app:srcCompat="@drawable/ic_play_to_pause" />
Обратите внимание, что мы используем контрол из android support библиотеки, а также указываем drawable в app:srcCompat – все это позволит использовать animated-vector в проектах API >= 15.
Осталось лишь запустить анимацию. В коде пишем лишь одну строку:
((Animatable) imageView.getDrawable()).start();
В настройках проекта не забудьте поставить флаг
android {
compileSdkVersion 26
defaultConfig {
...
vectorDrawables.useSupportLibrary = true
}
...
}
Что мы получили в итоге? Смотрим результат ↓
К сожалению, стандартными способами мы не можем управлять анимацией. Мы не можем привязать ее к какому-то событию, например, swipe, чтобы иконка менялась как тот же hamburger при открытии Navigation Drawer. Получается, что управлять vector animation нельзя? Не совсем так, но это уже совсем другая история.