Polishing UI: Android StateListAnimator

Most of the time, we don’t spend time to develop our Android app’s UI, we just drag and drop views and start writing our app. I have observed that most of us don’t care that much about the user interface. And I believe that it’s wrong. Mobile developers should care about UI/UX too. I am not saying “Be an expert on mobile UI” but we should understand design language and it’s concept.

Previously I wrote something about material design shadows and I got lots of good feedback. I would like to thank all of you. “Mastering Shadows in Android” explains elevation and shadows in android. And also I applied these changes to my open source UI library. (Scaling Layout).

In this post, I also want to polish my library with StateListAnimator and show you step by step how I achieved that.

Contents

This blog post covers following topics.

Drawable States

In Android, there are 17 different states for the Drawable.

Maybe we don’t even know some of them. I am not going to deep dive into every state. Most of the time, we use pressed, enabled, windows focused, checked etc. If we don’t declare any state for a drawable, this means default state in Android.

We need to understand these states to write our custom StateListDrawable.

StateListDrawable

This is basically a list of drawable items and every item has it’s own state. We create an XML file under res/drawable folder to create StateListDrawable.

<item android:drawable="@drawable/i" android:state_pressed="true"/>

This is an item. It has two property. Drawable and State.

<selector>
<item
android:drawable="@drawable/p"
android:state_pressed="true"/>
<item
android:drawable="@drawable/default"/>
</selector>

This is a StateListDrawable. If we don’t declare any state for an item, as I said before, this means that default state.

Can I use ShapeDrawable?

Yes. Instead of using android:drawable, you can add a custom shape to your item. Here is the item with ShapeDrawable.

StateListDrawable

You can use StateListDrawable from API level 1. So there is no API level limitation on StateListDrawable.

<View
android:layout_width="50dp"
android:layout_height="50dp"
android:foreground="@drawable/state_list_drawable"
android:clickable="true"/>

That’s it. Now our view has state. When user press on it, it’s color will be changed. And user release it, It will have default state and color.

But wait. Clickable? Why did we add that attribute? Should we add that too? Yes. But only for custom views. It takes some time to find out. Buttons work perfectly without adding clickable because it is clickable by default. But If you want to use StateListDrawable for a View, ImageView, Custom View, etc. you need to add clickable attribute.

StateListDrawable

I added StateListDrawable and here is the commit. It is just like the example I gave above. When user clicks on the layout, layout gets colored. But Let’s make it better with StateListAnimator.

StateListAnimator

Remember when you click on FloatingActionButton and it’s Z value increased with an animation. It is the StateListAnimator behind the scene. Some of the material design widgets have it’s own StateListAnimator internally.

Let’s make it clear with the SO question.

If material design widgets have their own StateListAnimator internally, we can set them null to remove that feature (Don’t recommend it, It is developed for a reason.) And answer sounds more logical right now.

So, how can we create one?

To understand StateListAnimator, we need to understand property animation. I am not going to deep dive into property animation in this blog post. But at least, I want to show you the basics.

Property Animation

Here is the most basic example of the property in an object. X is a property.

class MyObject{

private int x;

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}
}

The property animation system is a robust framework that allows you to animate almost anything. You can define an animation to change any object property over time, regardless of whether it draws to the screen or not. A property animation changes a property’s (a field in an object) value over a specified length of time.

X is a property. T is a time. In property animation, X is updated in given time. This is basically how property animation works. The box can be a view or any object.

ValueAnimator is a base class for property animation. You can set an update listener to value animator and observe the property changes.

ObjectAnimator is a class that extends from ValueAnimator. You can use ObjectAnimator if you have following conditions;

  • You have an object(Any Class has some property)
  • You don’t want to observe value animator listener
  • You want to update object’s property automatically

So If we have a view (which is an object) and we want to update view’s property (x coordinate, y coordinate, rotation, translation or any property that the view has getter/setter of the property), we can use ObjectAnimator. Let’s continue to create StateListAnimator.

<selector>

<item android:state_pressed="true">
<objectAnimator
android:duration="200"
android:propertyName="translationZ"
android:valueTo="6dp"
android:valueType="floatType" />

</item>

<item>
<objectAnimator
android:duration="200"
android:propertyName="translationZ"
android:valueTo="0dp"
android:valueType="floatType"/>

</item>

</selector>
FAB button animates its property “translationZ” on pressed and released

As I said before, we can use object’s property directly without observing changes in animator. every View has translationZ property. So we can directly animate translationZ using ObjectAnimator.

We can also combine multiple <objectAnimator>s in a <set>. Let’s change another property of the View. Scale X and Scale Y.

Here is the result! Now It is also scaled up when the user pressed. Here is the commit.

You can also define other properties in your animator.xml. Here you can find more information about using ObjectAnimator.

That’s all. I am planning to write something about ValueAnimator and ObjectAnimator. It is a great API animate an object.

Happy coding.

Software Engineer at Storytel

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