Работа с анимацией. AnimatedVectorDrawableCompat

В этой стате хотел бы всем рассказать и показать на практике, как можно делать анимацию в Android приложении при помощи AnimatedVectorDrawableCompat, например свои кастомные кнопки, ImageView, FloatingActionButton.


На сегодняшний день информации по этому поводу в сети не так много, точней ее совсем — нет. Все, что мне удалось найти — это недавние представленные новшества Google, а именно: 

Статья из Android Developer Blog
Видео с Google I/O 2016
Android Reference

Этого по сути мало, чтобы понять, как применить на практике AnimatedVectorDrawableCompat.

Теперь непосредственно перейдем к применению. 

На первом этапе нам нужно избавиться от того, чтоб фреймворк превращал иконку в .png. С версии 23.3.0 можно использовать .xml и для это нужно в Gradle app level добавить следующий flag:

android { ... defaultConfig { ... vectorDrawables.useSupportLibrary = true } }

И в зависимость подключить последнюю версию AppComapt:

dependencies { ... compile 'com.android.support:appcompat-v7:23.4.0' }

Далее, в примере я буду использовать квадрат (синий), который будет немного накрывать своими углами круг (красный). 
На выходе мы должны задействовать 2 объекта и заставить их непрерывно двигаться соответственно по оси X (квадрат) и Y (круг).

Шаги: 

1) 

Создаем Drawable Resource File, называем файл — icon.xml и кладем в папку drawable:

<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="120dp" android:height="120dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <group android:name="circle" android:scaleX=".7" android:scaleY=".7" android:pivotX="12" android:pivotY="12"> <path android:fillColor="#ff0000 " android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/> </group> <group android:name="square" android:scaleX="1" android:scaleY="1" android:pivotX="12" android:pivotY="12"> <path android:fillColor="#FF0000ff" android:pathData="M6,6h12v12H6z"/> </group> </vector>

2) 

Для хранения анимации в своем проекте мы создаем папку animator — res/animator
В нее мы положим два объекта и назовем их соответственно:

a) circle.xml:


<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:propertyName="translateX" android:valueType="floatType" android:valueFrom="0" android:valueTo="5" android:repeatMode="reverse" android:repeatCount="infinite" android:duration="250" /> </set>

b) square.xml

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:propertyName="translateY" android:valueType="floatType" android:valueFrom="0" android:valueTo="5" android:repeatMode="reverse" android:repeatCount="infinite" android:duration="250" /> </set>

Здесь же мы и указали, что объекты будут двигать по оси X и Y, откуда будут начинать движение, а также бесконечность движений.

Если у вас больше именованных групп, которые нужно анимировать — то вот в этой директории их и нужно создавать, соответсвенно и больше групп будут в основном файле — icon.xml

3) 

Теперь создаем непосредственно анимированный файл, на который будем ссылаться в layout или в коде — res/drawable/anim_icon:


<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/icon"> <target android:name="square" android:animation="@animator/square" /> <target android:name="circle" android:animation="@animator/circle" /> </animated-vector>

Примечание: Android Studio подчёркивает красным animated-vector (если мин.версия проекта меньше 21), но если вы подключили flag, как указанно в начале — все заработает.

4) 

Теперь мы можем обращаться к анимированным векторам в xml. Это может быть — ImageView, ImageButton, FloatingActinonButton:


<LinearLayout ... xmlns:app="http://schemas.android.com/apk/res-auto"/> <ImageView app:srcCompat="@drawable/anim_icon" ... /> </LinearLayout>

5) 

Обращаемся из кода к векторам. Здесь я также повесил OnClickListener и сохранил состояние при перевороте:


static final String STATE_ANIM = "isAnim"; boolean mIsAnim; AnimatedVectorDrawableCompat avd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView imageView = (ImageView) findViewById(R.id.imageView); if (imageView != null) { Drawable drawable = imageView.getDrawable(); avd = (AnimatedVectorDrawableCompat) drawable; if (savedInstanceState != null) { mIsAnim = savedInstanceState.getBoolean(STATE_ANIM); if (mIsAnim) { avd.start(); } } imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (avd.isRunning()) { avd.stop(); mIsAnim = false; } avd.start(); mIsAnim = true; } }); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_ANIM, mIsAnim); } }

Примечание: не забудьте подтянуть зависимость:

import android.support.graphics.drawable.AnimatedVectorDrawableCompat;

Результат проделанной работы:


Недавно появилась возможность объединить файлы my_vector.xml и anim_vector в одном anim_vector (теперь отдельный файл res/drawable/my_vector.xml не нужен), а также добавить сюда и файлы-аниматоры (objectAnimator) таким образом получится один файл на всю анимацию.

Представили это Google на I/O, но к сожалению — не работает. На видео с 14 минуты говориться об этом.