Animating a strike through on Android with Animated​Vector​Drawable and Animated​State​List​Drawable

Tiger Oakes
Aug 12, 2019 · 7 min read

We recently added a neat little animation to Firefox Preview:

Image for post
Image for post

In Firefox Preview, you can grant a website access to your location and microphone. When you toggle those permissions off, a line appears and grows diagonally through the original icon as it fades to gray. To create the animation, I considered many details such as colors, lines, curves, and clip paths.

Color

Shield icon transitions from purple to gray
Shield icon transitions from purple to gray

In Android, an animation can be broken down into three states: The start, the end, and the in-between. Android automatically creates the in-between parts of the animation, so you just need to define the start and the end.

For color, that’s pretty simple. When the permission is turned on, the icon is purple. When the permission is turned off, the icon is gray. Android handles the transition between the two colors.

You can preview animations with a tool called Shape Shifter.

The line

Unlike colors, which are single values, shapes are more complex. Even a simple line has multiple points to define its edges.

In Firefox, our icons are defined as vectors, meaning that an image file specifies some points and the computer connects the dots. This is different than bitmap images which store many coloured squares. Since the computer is just connecting dots, the image can be scaled up without losing any detail.

Android can also animate these dots. A line (really a thin rectangle) can be represented as 4 dots for each corner. When it disappears, it’s really just moving the dots so that the rectangle is so small you can’t see it.

Here you can see how the animation looks, with the start of the animation on the left and the end on the right.

Square line growing animation
Square line growing animation

The curves

Naive curved line growing animation
Naive curved line growing animation

This animation for square lines is great, but it doesn’t work for Firefox. The lines we use for Firefox’s icons are curved at the end, rather than flat. When we try to make this line animate, the ends shrink and grow oddly. Look closely at the upper right corner of the animation and how the line width adjusts.

That’s not ideal. Luckily there’s another way to hide the line when it shrinks.

Clip paths

You can hide parts of an image by putting it behind an “ clip path “, a special path that hides everything outside of it. It’s akin to a cookie cutter that extracts a shape from the rest of the cookie dough. Outside the clip path, the line becomes invisible.

SVG emoji + clip path = SVG emoji with clip path applied
SVG emoji + clip path = SVG emoji with clip path applied

By using a clip path, we can hide the end of the line without changing the relative positioning of its dots.

Curved line animating, with clip path and edges visible
Curved line animating, with clip path and edges visible

The spacing

If we put our animated line on top of another icon, this is what we end up with.

Strike through with no spacing
Strike through with no spacing

The line unfortunately blends in with the icon. To emphasize the strike through, we want to create a small gap right under the line and create something like this:

Static icon with line through it and a gap
Static icon with line through it and a gap

Luckily, we already know how to hide parts of an icon. We can use a clip path again. Since clip paths are just another shape created by connecting dots, they can also be animated in parallel to the original line.

Transition with just the clip path
Transition with just the clip path

Here’s the final product. Using a combination of color transitions, shape transitions, and clip paths we’ve achieved a clean line effect. Looks great!

Completed animation
Completed animation

Using the animation on Android

Android has tools to create an animation like this with just XML, without Java or Kotlin. You need to create a few different files to represent different states and how to transition between them. The finished files are available to download from GitHub too.

First of all we start with a Vector Drawable, which contains the icons and the paths we designed before. This goes inside the Android project’s drawables folder.

res/drawables/ic_protection_enabled.xml

We also create a second Vector Drawable to represent the icon with a line through it.

res/drawables/ic_protection_disabled.xml

Unfortunately there’s no simple way to play the animation in reverse, for when you want to remove the strike-through. You need to create two different sets of animations for the enable → disable transition and disable → enable transition.

Creating animation resources

Now that we have the base icon resource, we create a property animator for each path that we want to animate. These files go inside the res/animator resources folder. We animate three paths: The color of the main icon ( android:name="icon"), the shape of the clip path ( android:name="strike_thru_gap"), and the color and shape of the line ( android:name="strike_thru_path"). We also have to create another 3 property animators for the reverse direction.

Changing the color of the icon

res/animator/icon_enabled_to_disabled.xml

res/animator/icon_disabled_to_enabled.xml

We create two ObjectAnimators representing the color property of an object. These two animator files are nearly identical, but the android:valueFrom and android:valueTo fields have been flipped. These fields indicate the starting and ending values (in this case, the two colors). android:propertyName specifies the attribute that we're animating, and android:valueType specifies the type of the values in valueFrom and valueTo. android:duration specifies the length of the animation, in milliseconds. The value of "500" corresponds to 500 milliseconds or half a second.

Changing the shape of the clip path

To change the shape of the clip path, create another ObjectAnimator like before. Instead of animating between two colors, we now animate between two paths.

res/animator/strike_thru_gap_​enabled_to_disabled.xml

The valueType is now "pathType" as the values represent shape paths rather than colors. Again, you can create the strike_thru_gap_disabled_to_enabled.xml file by copying strike_thru_gap_enabled_to_disabled.xml and switching around valueFrom with valueTo. (Or download the source code.)

Changing two values on the same path at once

Finally we create animators for the color and shape of the line. Since there are two values to animate, we use a AnimatorSet. The set is just a simple container for other animation elements.

res/animator/strike_thru_path_​enabled_to_disabled.xml

The two individual object animators are very similar to the previous shape and color object animators we wrote. However, they are still distinct animators since the path values are different. Here, they run in tandem on the line.

Again, the corresponding animator for the reverse direction is left as an exercise for you. You can also just download the source code.

Using Animated Vector Drawables

At this point we’ve created the icon, and created animators for each part of the icon we want to animate. Now it’s time to start putting them together.

We create two Animated​Vector​Drawables to represent the enable → disable animation and disable → enable animation.

res/drawable/ic_protection_​enabled_to_disabled.xml

res/drawable/ic_protection_​disabled_to_enabled.xml

These <animated-vector> tag has an android:drawable attribute where we specify the drawable that we want to animate. The two VectorDrawables we created above are referenced by name here.

Inside the tag, we create <target> tags for each path we want to animate. The android:name field indicates the name of the path to animate, as specified in the VectorDrawables. The android:animator tag references one of the property animators we created. Each animator is matched to its corresponding animation and target.

The Animated​State​List​Drawable

Now we have two assets that contain all our animation code. Now, we create one final asset that references these two.

Android has a built in concept of “states” for its views, such as pressed when a user presses on a view or checked when a checkbox is selected. The enabled state is a nice general-purpose state that we'll use to represent whether or not the icon should have the line drawn through it.

The State​List​Drawable is a special drawable type that changes the drawable displayed within depending on the state of its container. We can reference our static VectorDrawables again for the enabled and disabled states.

The android:state_enabled attribute specifies which drawable corresponds to the enabled state. The item with no modifier will automatically be used for the disabled state.

While this will change the displayed icon, there’s no animation when switching between the two. For that, we need to use an Animated​State​List​Drawable. This drawable enhances the StateListDrawable by allowing you to specify transitions between states.

res/drawable/ic_protection.xml

We change the XML tag from <selector> to <animated-selector> and add two <transition> elements. The transitions specify their starting state and ending state with the android:fromId and android:toId attributes, which correspond to the values in the <item android:id="..."> elements.

Actually displaying the icon

Finally we have a single super special drawable asset to use in our app. It can be used just like any other drawable, including in an ImageView.

From your code, just change the enabled value and you'll see the icon automatically transition!

Sample code preview
Sample code preview

This article has broken down how to implement animation in Android step-by-step. The same principles apply to not only strike-throughs, but other animations as well. In addition to colors and paths, you can animate position, rotation, transparency, and more. I can’t wait to see what you all build!

Originally published at https://tigeroakes.com on August 12, 2019.

Firefox Mobile Engineering

News, notes and ramblings from the mobile teams at Mozilla

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store