Предлагаю вашему вниманию перевод статьи "VectorDrawables – Part 1" с сайта blog.stylingandroid.com.
По долгу службы потребовалось мне как-то разобраться с векторной графикой. Во время поиска наткнулся я на серию статей под названием “VectorDrawable” в блоге https://blog.stylingandroid.com/. Ответов на все интересующие меня вопросы я, конечно, не нашел, но статьи очень понравились своей последовательностью и четко выверенным объемом необходимого материала. Решил поделиться переводом этих статей с обитателями хабра.
Я не переводил названия, activity, bitmap и тому подобное, потому что считаю, что так легче воспринимать информацию, ведь разработчики, в силу профессии, эти слова в русском варианте практически никогда не у потребляют. Далее следует перевод:
Одна из действительно интересных новых фишек в Lollipop – это включение VectorDrawable и связанных с ним классов, которые обеспечивают чрезвычайно мощные новые возможности для добавления сложной векторной графики (позволяет гораздо удобнее масштабировать изображения не зависимо от размеров экрана и плотности, чем растровые изображения), а также предоставляет несколько мощных инструментов для анимации оных. В этой серии статей мы рассмотрим некоторые из преимуществ, которые они нам дают. Так же рассмотрим, как можно получить действительно впечатляющие результаты из относительно небольшого количества кода.
Векторная графика – способ описания графических элементов используя геометрические фигуры. Они особенно хорошо подходят для графических элементов, созданных в приложениях, таких как Adobe Illustrator или Inkscape, где простые геометрические формы могут быть объединены в гораздо более сложные элементы. Работа с растровой графикой, с другой стороны, определяет значение цвета для каждого пикселя и особенно хорошо подходит для фото. Большим преимуществом использования векторной графики (в соответствующих случаях) является то, что изображения рендерятся в рантайме и размеры автоматически высчитываются в зависимости от плотности пикселей. Таким образом получается четкая картинка с плавными линиями, независимо от возможностей устройства. Векторные картинки, как правило, занимают значительно меньший объем памяти, чем их растровый аналог. Однако, векторные изображения требуют больше вычислительных мощностей для отрисовки, что может быть проблемой при большом количестве сложных графических элементах.
Векторная графика в андроиде была реализована с использованием нового класса – VectorDrawable, который был введен в Lollipop. Это означает, что для графических элементов, которые хорошо подходят для векторного представления мы можем заменить растровые изображения в папках mdpi, hdpi, xhdpi, xxhdpi, и xxxhdpi на один VectorDrawable в папке Drawable, который, с большой вероятностью, займет даже меньше пространства на диске, чем растровое изображение для mdpi.
Чтобы продемонстрировать это, давайте рассмотрим следующий файл svg (найти его можно по ссылке https://code.google.com/archive/p/svg-android/downloads):
Этот svg-файл занимает 2265 байт, если мы отрисуем его в bitmap с размерами 500 х 500 пикселей, и сохраним как png, тогда он займет уже 13272 байта, плюс к этому, мы должны будем использовать несколько таких картинок для разный плотностей экрана. Но SVG – это не то же самое, что VectorDrawable, поэтому мы не можем использовать его непосредственно. Тем не менее, VectorDrawable поддерживает некоторые элементы SVG. Основные компоненты, которые мы будем использовать из нашего SVG – это path. Давайте посмотрим на исходный код SVG:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g id="max_width__x2F__height" display="none">
<path display="inline" d="M499.001,1v498H1V1H499.001 M500.001,0H0v500h500.001V0L500.001,0z"/>
</g>
<g id="androd">
<path fill="#9FBF3B" d="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.199
L294.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.41
c-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.272
c-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 fill="#FFFFFF" d="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08
c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438"/>
<path fill="#FFFFFF" d="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08
c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438"/>
<path fill="#9FBF3B" d="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.09
c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z"/>
<path fill="#9FBF3B" d="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744
c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744
c0,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.489
H140.396z"/>
<path fill="#9FBF3B" d="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.09
c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z"/>
</g>
</svg>
Немного разберемся. Есть некоторые атрибуты родительского элемента , которые определяют размер 500х500, Есть элемент (group), который определяет границы – его мы будем игнорировать. Есть еще один элемент с id = “android”. Это и есть изображение логотипа, которое нам нужно. Он состоит из шести элементов , которые определяют голову, правый глаз, левый глаз, левая рука, тело и ноги, правая рука. Атрибут “fill” определяет цвет заливки (и мы можем видеть, что все они зеленые, за исключением глаз, которые залиты белым цветом), а атрибут “d” содержит маршрут линий, из которых состоит элемент. Для тех, кто хочет разобраться более детально в элементе , следует изучить SVG Path Specification, но для данной статьи это не важно, потому что мы можем просто взять их, как они есть, и использовать в наших VectorDrawables.
Итак, давайте создадим наш VectorDrawable:
<?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">
<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" />
<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="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" />
<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>
</vector>
Мы создали родительский элемент , который содержит информацию о размерах изображения, внутрь которого поместили элемент с шестью элементами , которые были немного модифицированы, по сравнению с svg – файлом. В данной статье поле “name” служит только для облегчения понимая того, где какой элемент. В следующих статьях они буду использоваться. Получившийся файл по-прежнему может похвастаться скромным размером в 2412 байт.
Теперь мы можем использовать этот файл как любой другой drawable:
<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/android"
android:contentDescription="@null" />
</RelativeLayout>
… и если мы запустим это, то увидим красивую отрисовку:
Так что теперь мы можем существенно уменьшить размер APK, если мы используем VectorDrawable, где это уместно. Так же это позволяет упростить разработку приложения, особенно, если нужно добавлять поддержку новых плотностей экрана. Тем не менее, это не все, на что способен VectorDrawable. В следующей части статьи мы рассмотрим, как его анимировать.
Исходники к этой части статьи можно найти здесь.
dzigoro
А слух был, мол, в compatibility это тоже затащили. Это правда?
IIblBko
Да. Это правда. Статья, которую переводил, не самая свежая. Сейчас в саппорт либе есть поддержка VectorDrawable и более старых версий. По памяти не скажу насколько старые версии они начали поддерживать.
kaftanati
Правда-правда.
danikula
Но в весьма ограниченном виде. Нельзя например использовать векторные картинки в
drawableLeft
и прочихdrawable*
дляTextView
, нельзя использовать для иконок системных нотификаций. Зато смело можно использовать вImageView
при помощи нового атрибутаapp:srcCompat
.