Статьи

Использование Android VectorDrawable Class

Хотя Android не поддерживает SVG (Scalable Vector Graphics) напрямую, Lollipop представил новый класс VectorDrawable , который позволяет дизайнерам и разработчикам рисовать ресурсы аналогичным образом, используя только код.

В этой статье вы узнаете, как создать VectorDrawable с файлами XML и анимировать их в своих проектах. Это поддерживается только для устройств под управлением Android 5.0 или выше, и в настоящее время нет реализаций библиотеки поддержки. Исходные файлы этого руководства можно найти на GitHub.

Основное сходство между 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.

Теперь, когда вы знаете, как создавать изображения, используя только код, пришло время немного повеселиться и оживить их. В следующей анимации вы заметите, что каждая из групп проводов пульсирует к процессору и от него.

Пример анимированного VectorDrawables

Для достижения этого эффекта вам нужно будет обернуть каждый раздел, который вы хотите анимировать, в <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-кода.

Обычный вариант использования 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.