В предыдущей статье мы рассмотрели, как преобразовать существующий svg-файл в VectorDrawable, который позволяет заменить много растровых изображений на одно, меньшее по размеру и более простое в обслуживании. Однако, это не все полезности, которые можно извлечь из VectorDrawable. Его можно анимировать. Это мы и рассмотрим в данной статье, заставив логотип андроид пожимать плечами.
Анимация, которую мы задумали — это простое движение по оси Y. Мы хотим перемещать голову и руки, но оставить неподвижным тело. На первый взгляд все это выглядит довольно сложно, потому что это все элементы одного Drawable. Но в Lollipop, вместе с VectorDravable был введен компонент, который очень сильно упрощает нам задачу. А именно — AnimatedVectorDrawable. В предыдущей статье мы дали каждому элементу path имя, и теперь можем применить анимацию для различный path в пределах VectorDrawable. На практике это оказалось немного затруднительно, потому что path не имеет таких атрибутов, как translateX и translateY, которые мы можем контролировать аниматором. Элемент group имеет необходимые нам атрибуты, поэтому мы обернули голову и руки в grope:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:viewportWidth="500" android:viewportHeight="500" android:width="500px" android:height="500px"> <group android:name="android"> <group android:name="head_eyes"> <path android:name="head" android:fillColor="#9FBF3B" android:pathData="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298" /> <path android:name="left_eye" android:fillColor="#FFFFFF" android:pathData="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438" /> <path android:name="right_eye" android:fillColor="#FFFFFF" android:pathData="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438" /> </group> <group android:name="arms"> <path android:name="left_arm" android:fillColor="#9FBF3B" android:pathData="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z" /> <path android:name="right_arm" android:fillColor="#9FBF3B" android:pathData="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z" /> </group> <path android:name="body" android:fillColor="#9FBF3B" android:pathData="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489H140.396z" /> </group> </vector>
Теперь мы можем написать drawable с animated-vector, чтобы применить анимацию к нужным группам, нашего изображения:
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/android"> <target android:animation="@animator/shrug" android:name="head_eyes" /> <target android:animation="@animator/shrug" android:name="arms" /> </animated-vector>
Я знаю, что можно было объединить голову и руки в одну группу, но сознательно разделил на две, чтобы показать, как несколько групп можно анимировать при помощи одного animated-vector.
Родительский элемент "animated-vector" определяет VectorDrawable, который мы будем анимировать. А внутренние элементы target определяют тип анимации и группу, к которой будет применена данная анимация.
Существуют разные параметры, которые можно анимировать у различных элементов, таких как vector, group, clip-path и path. Поэтому нужно посмотреть VectorDravable JavaDocs, чтобы узнать какие элементы использовать для конкретной анимации. Например, изменять параметр tint, необходимо у элемента vector, тогда как изменение цвета заливки нужно делать у параметра path.
Напишем простую анимацию изменения положения по Y для пожимания плечами нашего андроида:
<?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="-10" android:repeatMode="reverse" android:repeatCount="infinite" android:duration="250" /> </set>
Для того чтобы запустить эту анимацию нам нужно сделать пару вещей. Для начала мы должны изменить Drawable, что мы установили на ImageView в нашем layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".VectorDrawablesActivity"> <ImageView android:id="@+id/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/animated_android" android:contentDescription="@null" /> </RelativeLayout>
Если мы запустим приложение, то увидим статичное изображение, потому что анимацию необходимо запустить из activity:
public class VectorDrawablesActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_vector_drawables); ImageView androidImageView = (ImageView) findViewById(R.id.android); Drawable drawable = androidImageView.getDrawable(); if (drawable instanceof Animatable) { ((Animatable) drawable).start(); } } }
Если запустить приложение теперь, то мы увидим, что анимация работает и применяется только к нужным нам частям изображения:
В следующей статье мы глубже изучим и рассмотрим некоторые действительно крутые методы анимации, которые можно сделать при помощи AnimatedVectorDrawable.
Исходный код для этой статьи доступен здесь.