Вступление
Хотя Android не поддерживает SVG (Scalable Vector Graphics) напрямую, Lollipop представил новый класс VectorDrawable , который позволяет дизайнерам и разработчикам рисовать ресурсы аналогичным образом, используя только код.
В этой статье вы узнаете, как создать VectorDrawable с файлами XML и анимировать их в своих проектах. Это поддерживается только для устройств под управлением Android 5.0 или выше, и в настоящее время нет реализаций библиотеки поддержки. Исходные файлы этого руководства можно найти на GitHub.
1. Создание векторного рисования
Основное сходство между VectorDrawable и стандартным SVG-изображением заключается в том, что оба они нарисованы с использованием значения пути . Понимая, как SVG пути нарисованы вне рамок данной статьи, официальная документация может быть найдена на сайте W3C . Для этой статьи вам просто нужно знать, что тег path — это место, где происходит рисование. Давайте посмотрим на файл SVG, который рисует следующее изображение:

В этом изображении пять основных частей:
- квадрат для корпуса процессора, состоящий из двух арок
- четыре группы из пяти линий, которые представляют провода процессора
Следующий код рисует это изображение как SVG:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?xml version=»1.0″ encoding=»utf-8″?>
<!DOCTYPE svg PUBLIC «-//W3C//DTD SVG 1.1//EN» «http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd»>
<svg version=»1.1″ xmlns=»http://www.w3.org/2000/svg» xmlns:xlink=»http://www.w3.org/1999/xlink» x=»0px» y=»0px»
width=»512px» height=»512px» viewBox=»0 0 512 512″ style=»enable-background:new 0 0 512 512;»
<path id=»cpu» d=»
M341.087,157.478c7.417,0,13.435,6.018,13.435,13.435v170.174 c0,7.417-6.018,13.435-13.435,13.435H170.913 c-7.417,0-13.435-6.018-13.435-13.435V170.913 c0-7.417,6.018-13.435,13.435-13.435H341.087z
M390.348,157.478 c0-19.785-16.041-35.826-35.826-35.826H157.479c-19.785,0-35.826,16.041-35.826,35.826v197.043 c0,19.785,16.041,35.826,35.826,35.826h197.043c19.785 0,35.826-16.041,35.826-35.826V157.478z
M193.304,408.261V462h-17.913 v-53.739H193.304z
M264.957,408.261V462h-17.914v-53.739H264.957z
M300.783,408.261V462h-17.914v-53.739H300.783z
M229.13,408.261 V462h-17.913v-53.739H229.13z
M336.609,408.261V462h-17.914v-53.739H336.609z
M193.304,50v53.739h-17.913V50H193.304z
M264.957,50 v53.739h-17.914V50H264.957z
M300.783,50v53.739h-17.914V50H300.783z
M229.13,50v53.739h-17.913V50H229.13z
M336.609,50v53.739 h-17.914V50H336.609z
M408.261,318.695H462v17.914h-53.739V318.695z
M408.261,247.043H462v17.914h-53.739V247.043z
M408.261,211.217 H462v17.913h-53.739V211.217z
M408.261,282.869H462v17.914h-53.739V282.869z
M408.261,175.391H462v17.913h-53.739V175.391z
M50,318.695h53.739v17.914H50V318.695z
M50,247.043h53.739v17.914H50V247.043z
M50,211.217h53.739v17.913H50V211.217z
M50,282.869 h53.739v17.914H50V282.869z
M50,175.391h53.739v17.913H50V175.391z» />
</svg>
|
Хотя это может показаться немного сложным, на самом деле вам не нужно полностью понимать, как все нарисовано для реализации VectorDrawable в вашем коде. Однако следует отметить, что я разделил каждый из пяти разделов на свой уникальный блок в коде для удобства чтения.
Верхняя секция состоит из двух арок для рисования скругленного квадрата, а последующие секции представляют нижнюю, верхнюю, правую и левую группы линий соответственно. Чтобы превратить этот SVG-код в VectorDrawable , сначала необходимо определить vector объект в XML. Следующий код взят из файла vector_drawable_cpu.xml в примере кода для этой статьи.
|
1
2
3
4
5
6
7
|
<vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:height=»64dp»
android:width=»64dp»
android:viewportHeight=»600″
android:viewportWidth=»600″ >
</vector>
|
Далее вы можете добавить в путь данные. Следующий код разбит на пять разных тегов пути, а не на один большой путь.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:height=»64dp»
android:width=»64dp»
android:viewportHeight=»600″
android:viewportWidth=»600″ >
<path
android:name=»cpu»
android:fillColor=»#000000″
android:pathData=»
M341.087,157.478 c7.417,0,13.435,6.018,13.435,13.435 v170.174c0,7.417-6.018,13.435-13.435,13.435 H170.913 c-7.417,0-13.435-6.018-13.435-13.435V170.913c0-7.417,6.018-13.435,13.435-13.435H341.087z
M390.348,157.478 c0-19.785-16.041-35.826-35.826-35.826H157.479c-19.785,0-35.826,16.041-35.826,35.826v197.043 c0,19.785,16.041,35.826,35.826,35.826h197.043c19.785,0,35.826-16.041,35.826-35.826V157.478z»
/>
<path
android:name=»wires_bottom»
android:fillColor=»#000000″
android:pathData=»
M193.304,408.261V462h-17.913 v-53.739H193.304z
M264.957,408.261V462h-17.914v-53.739H264.957z
M300.783,408.261V462h-17.914v-53.739H300.783z
M229.13,408.261 V462h-17.913v-53.739H229.13z
M336.609,408.261V462h-17.914v-53.739H336.609z»
/>
<path
android:name=»wires_top»
android:fillColor=»#000000″
android:pathData=»
M193.304,50v53.739h-17.913V50H193.304z
M264.957,50 v53.739h-17.914V50H264.957z
M300.783,50v53.739h-17.914V50H300.783z
M229.13,50v53.739h-17.913V50H229.13z
M336.609,50v53.739 h-17.914V50H336.609z»
/>
<path
android:name=»wires_right»
android:fillColor=»#000000″
android:pathData=»
M408.261,318.695H462v17.914h-53.739V318.695z
M408.261,247.043H462v17.914h-53.739V247.043z
M408.261,211.217 H462v17.913h-53.739V211.217z
M408.261,282.869H462v17.914h-53.739V282.869z
M408.261,175.391H462v17.913h-53.739V175.391z»
/>
<path
android:name=»wires_left»
android:fillColor=»#000000″
android:pathData=»
M50,318.695h53.739v17.914H50V318.695z
M50,247.043h53.739v17.914H50V247.043z
M50,211.217h53.739v17.913H50V211.217z
M50,282.869 h53.739v17.914H50V282.869z
M50,175.391h53.739v17.913H50V175.391z»
/>
</vector>
|
Как видите, каждый раздел пути просто использует атрибут pathData для рисования. Теперь вы можете включить XML-файл VectorDrawable в качестве отрисовки в стандартный ImageView и он будет масштабироваться до любого размера, необходимого вашему приложению, без необходимости использования какого-либо кода Java.
2. Векторные анимационные рисунки
Теперь, когда вы знаете, как создавать изображения, используя только код, пришло время немного повеселиться и оживить их. В следующей анимации вы заметите, что каждая из групп проводов пульсирует к процессору и от него.

Для достижения этого эффекта вам нужно будет обернуть каждый раздел, который вы хотите анимировать, в <group> . Обновленная версия vector_drawable_cpu.xml выглядит следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:height=»64dp»
android:width=»64dp»
android:viewportHeight=»600″
android:viewportWidth=»600″ >
<group
android:name=»cpu_box»>
<path
android:name=»cpu»
android:fillColor=»#000000″
android:pathData=»
M341.087,157.478 c7.417,0,13.435,6.018,13.435,13.435 v170.174c0,7.417-6.018,13.435-13.435,13.435 H170.913 c-7.417,0-13.435-6.018-13.435-13.435V170.913c0-7.417,6.018-13.435,13.435-13.435H341.087z
M390.348,157.478 c0-19.785-16.041-35.826-35.826-35.826H157.479c-19.785,0-35.826,16.041-35.826,35.826v197.043 c0,19.785,16.041,35.826,35.826,35.826h197.043c19.785,0,35.826-16.041,35.826-35.826V157.478z «/>
</group>
<group
android:name=»bottom»>
<path
android:name=»wires_bottom»
android:fillColor=»#000000″
android:pathData=»
M193.304,408.261V462h-17.913 v-53.739H193.304z
M264.957,408.261V462h-17.914v-53.739H264.957z
M300.783,408.261V462h-17.914v-53.739H300.783z
M229.13,408.261 V462h-17.913v-53.739H229.13z
M336.609,408.261V462h-17.914v-53.739H336.609z» />
</group>
<group android:name=»top»>
<path
android:name=»wires_top»
android:fillColor=»#000000″
android:pathData=»
M193.304,50v53.739h-17.913V50H193.304z
M264.957,50 v53.739h-17.914V50H264.957z
M300.783,50v53.739h-17.914V50H300.783z
M229.13,50v53.739h-17.913V50H229.13z
M336.609,50v53.739 h-17.914V50H336.609z » />
</group>
<group android:name=»right»>
<path
android:name=»wires_right»
android:fillColor=»#000000″
android:pathData=»
M408.261,318.695H462v17.914h-53.739V318.695z
M408.261,247.043H462v17.914h-53.739V247.043z
M408.261,211.217 H462v17.913h-53.739V211.217z
M408.261,282.869H462v17.914h-53.739V282.869z
M408.261,175.391H462v17.913h-53.739V175.391z» />
</group>
<group android:name=»left»>
<path
android:name=»wires_left»
android:fillColor=»#000000″
android:pathData=»
M50,318.695h53.739v17.914H50V318.695z
M50,247.043h53.739v17.914H50V247.043z
M50,211.217h53.739v17.913H50V211.217z
M50,282.869 h53.739v17.914H50V282.869z
M50,175.391h53.739v17.913H50V175.391z» />
</group>
</vector>
|
Далее вы захотите создать аниматоры для каждого типа анимации. В этом случае есть один для каждой группы проводов в общей сложности четыре. Ниже приведен пример анимации верхней группы, и вам также понадобится анимация для нижней, левой и правой сторон. Каждый из XML-файлов аниматора можно найти в примере кода.
|
01
02
03
04
05
06
07
08
09
10
11
|
<?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>
|
Как вы можете видеть, propertyName установлено в translateY , что означает, что анимация будет двигаться вдоль оси Y. valueFrom и valueTo контролируют valueTo и конечное местоположение. Если установить repeatMode в reverse и repeatCount в infinite время, анимация будет repeatCount infinite , пока не будет видим VectorDrawable . duration анимации установлена на 250 , то есть время в миллисекундах.
Чтобы применить анимацию к вашему рисуемому файлу, вам нужно будет создать новый XML-файл animated-vector чтобы связать аниматоры с группами VectorDrawable . Следующий код используется для создания файла animated_cpu.xml .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
<?xml version=»1.0″ encoding=»utf-8″?>
<animated-vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:drawable=»@drawable/vector_drawable_cpu»>
<target
android:animation=»@animator/pulse_top»
android:name=»top» />
<target
android:animation=»@animator/pulse_right»
android:name=»right» />
<target
android:animation=»@animator/pulse_left»
android:name=»left» />
<target
android:animation=»@animator/pulse_bottom»
android:name=»bottom» />
</animated-vector>
|
Когда все ваши XML готовы к работе, вы можете использовать animated_cpu.xml рисовать в ImageView чтобы отобразить его.
|
1
2
3
4
5
|
<ImageView
android:id=»@+id/cpu»
android:layout_width=»64dp»
android:layout_height=»64dp»
android:src=»@drawable/animated_cpu» />
|
Чтобы запустить анимацию, вам нужно получить экземпляр Animatable из ImageView и start вызов.
|
1
2
3
4
5
|
ImageView mCpuImageView = (ImageView) findViewById( R.id.cpu );
Drawable drawable = mCpuImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
|
После того, как start был вызван, провода на образе процессора начнут двигаться с очень минимальным использованием Java-кода.
3. Преобразование векторных рисунков
Обычный вариант использования VectorDrawable — это преобразование одного изображения в другое, например, значок панели действий, который меняется со значка гамбургера на стрелку. Для этого пути источника и назначения должны следовать одинаковому формату для количества элементов. Для этого примера мы определим стрелки влево и вправо, показанные выше, в виде строк.
|
1
2
|
<string name=»left_arrow»>M300,70 l 0,70 -70,-70 0,0 70,-70z</string>
<string name=»right_arrow»>M300,70 l 0,-70 70,70 0,0 -70,70z</string>
|
Затем вам нужно создать начальный объект рисования для стрелки, используя путь для left_arrow . В примере кода он называется vector_drawable_left_arrow.xml .
|
01
02
03
04
05
06
07
08
09
10
11
|
<vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:height=»64dp»
android:width=»64dp»
android:viewportHeight=»600″
android:viewportWidth=»600″ >
<path
android:name=»left_arrow»
android:fillColor=»#000000″
android:pathData=»@string/left_arrow»/>
</vector>
|
Основное различие между анимацией процессора и преобразованием заключается в файле animator_left_right_arrow.xml .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<?xml version=»1.0″ encoding=»utf-8″?>
<set xmlns:android=»http://schemas.android.com/apk/res/android»>
<objectAnimator
android:duration=»1000″
android:propertyName=»pathData»
android:valueFrom=»@string/left_arrow»
android:valueTo=»@string/right_arrow»
android:valueType=»pathType»
android:repeatMode=»reverse»
android:repeatCount=»-1″/>
</set>
|
Вы заметите, что свойства valueFrom и valueTo ссылаются на данные пути для левой и правой стрелок, для valueType заданы pathType и propertyName устанавливается в pathData . Когда они установлены, аниматор узнает, как изменить один набор данных пути на другой. Когда аниматор закончил, вам нужно связать VectorDrawable с objectAnimator используя новый объект animated-vector .
|
1
2
3
4
5
6
7
8
|
<?xml version=»1.0″ encoding=»utf-8″?>
<animated-vector xmlns:android=»http://schemas.android.com/apk/res/android»
android:drawable=»@drawable/vector_drawable_left_arrow»>
<target
android:name=»left_arrow»
android:animation=»@animator/animator_left_right_arrows» />
</animated-vector>
|
Наконец, вам просто нужно связать анимированный объект рисования с ImageView и запустить анимацию в своем коде Java.
|
1
2
3
4
5
6
|
<ImageView
android:id=»@+id/left_right_arrow»
android:layout_width=»64dp»
android:layout_height=»64dp»
android:layout_below=»@+id/cpu»
android:src=»@drawable/animated_arrow» />
|
|
1
2
3
4
5
|
mArrowImageView = (ImageView) findViewById( R.id.left_right_arrow );
drawable = mArrowImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
|
Вывод
Как вы уже видели, класс VectorDrawable довольно прост в использовании и позволяет настраивать добавление простых анимаций. Хотя класс VectorDrawable в настоящее время доступен только для устройств под управлением Android 5.0 и более поздних версий, они будут иметь неоценимое значение, поскольку все больше устройств поддерживают Lollipop и будущие версии Android.