Вступление
Хотя 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.