An Interest In:
Web News this Week
- April 27, 2024
- April 26, 2024
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
Using Android's VectorDrawable Class
Introduction
While Android does not support SVGs (Scalable Vector Graphics) directly, Lollipop introduced a new class called VectorDrawable
, which allows designers and developers to draw assets in a similar fashion using only code.
In this article, you will learn how to create a VectorDrawable
with XML files and animate them in your projects. This is only supported for devices running Android 5.0 or above, and currently there are no support-library implementations. The source files of this tutorial can be found on GitHub.
1. Creating a Vector Drawable
The main similarity between a VectorDrawable
and a standard SVG image is that both are drawn out using a path value. While understanding how SVG paths are drawn is out of the scope of this article, official documentation can be found on the W3C website. For this article, you'll simply need to know that the path tag is where the drawing occurs. Let's take a look at the SVG file that draws out the following image:
There are five major parts to this image:
- a square for the CPU body made up of two arches
- four groups of five lines that represent the CPU's wires
The following code draws this image out as an SVG:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://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;" xml:space="preserve">
<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>
While this may look a little overwhelming, you don't actually need to fully understand how everything is drawn out to implement a VectorDrawable
in your code. However, it should be noted that I separated each of the five sections into their own unique block in the code for readability.
The top section consists of two arches to draw out the rounded square and the sections that follow represent the bottom, top, right, and left sets of lines respectively. To turn this SVG code into a VectorDrawable
, you first need to define the vector
object in XML. The following code is taken from the vector_drawable_cpu.xml file in the sample code for this article.
<vector xmlns:android="https://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600" >
</vector>
Next, you can add in the path data. The following code is broken up into five different path tags rather than one large path.
<vector xmlns:android="https://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>
As you can see, each path section simply uses the pathData
attribute for drawing. You can now include the VectorDrawable
XML file as a drawable in a standard ImageView
and it will scale to any size your app requires, without needing to use any Java code.
2. Animating Vector Drawables
Now that you know how to create images using only code, it's time to have a little fun and animate them. In the following animation, you'll notice that each of the groups of wires are pulsing towards and away from the CPU.
To achieve this effect, you will need to wrap each section that you want to animate in a <group>
tag. The updated version of vector_drawable_cpu.xml then looks like this:
<vector xmlns:android="https://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>
Next, you will want to create animators for each animation type. In this case, there is one for each group of wires for a total of four. Below is an example of the top group's animation and you will also need one for the bottom, left, and right. Each of the animator XML files can be found in the sample code.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://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>
As you can see, the propertyName
is set to translateY
, which means the animation will move along the Y axis. The valueFrom
and valueTo
control the begin and end location. By setting repeatMode
to reverse
and repeatCount
to infinite
, the animation will loop forever as long as the VectorDrawable
is visible. The duration
of the animation is set to 250
, which is the time in milliseconds.
To apply the animations to your drawable file, you will need to create a new animated-vector
XML file to associate the animators with the VectorDrawable
groups. The following code is used to create the animated_cpu.xml file.
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="https://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>
When all of your XML are ready to go, you can use the animated_cpu.xml drawable in an ImageView
to display it.
<ImageView
android:id="@+id/cpu"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/animated_cpu" />
To start your animation, you will need to get an instance of the Animatable
from the ImageView
and call start
.
ImageView mCpuImageView = (ImageView) findViewById( R.id.cpu );
Drawable drawable = mCpuImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
After start
has been called, the wires on the CPU image will start to move with very minimal Java code used.
3. Transforming Vector Drawables
A common use case for a VectorDrawable
is transforming one image into another, such as the action bar icon that changes from a hamburger icon into an arrow. To do this, both the source and destination paths must follow an identical format for the number of elements. For this example we will define the left and right facing arrows seen above as strings.
<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>
Next, you will need to create an initial drawable for an arrow using the path for left_arrow. In the sample code, it is called vector_drawable_left_arrow.xml.
<vector xmlns:android="https://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>
The main difference between the CPU animation and the transformation lies in the animator_left_right_arrow.xml file.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://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>
You'll notice the valueFrom
and valueTo
properties reference the path data for the left and right arrow, the valueType
is set to pathType
and propertyName
is set to pathData
. When these are set, the animator will know to change one set of path data to the other. When the animator is finished, you need to associate the VectorDrawable
with the objectAnimator
using a new animated-vector
object.
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="https://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>
Finally, you'll simply need to associate the animated drawable with an ImageView
and start the animation in your Java code.
<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" />
mArrowImageView = (ImageView) findViewById( R.id.left_right_arrow );
drawable = mArrowImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
Conclusion
As you have seen, the VectorDrawable
class is fairly straightforward to use and allows for a lot of customization to add simple animations. While the VectorDrawable
class is currently only available for devices running Android 5.0 and above, they will be invaluable as more devices support Lollipop and future Android releases.
Original Link:
TutsPlus - Code
Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.More About this Source Visit TutsPlus - Code