Create beautiful toggle buttons in android

We don’t talk about toggle switches as often as we should. Toggle switches are these amazing UI components that provide functionality to switch between states, like pause and play, on and off, active and inactive. Imagine how messy it would have been if we had to do these with some other UI component like buttons or something.

Toggle switches in Android are great with onCheckedChangedListener to aid us in reacting to state changes. Toggle buttons are quite simple with text and light indicating whether it is checked or unchecked. SwitchCompats are beautiful slider like toggle buttons, and they give a kind of physical feel of sliding the thumb on and off.

Google material design SwitchCompat

I admit! I love changing states of a toggle switch by dragging the thumb. But sometimes we need more from toggle buttons, like marking an item favourite and not favourite. The basic version will look bland for that functionality. So how can we customise it to suit our needs, let’s explore!

As you would have guessed we would need a drawable of our own to customise the look and feel of our toggle button. And since there are two states we would actually need two drawables to distinguish between those two states. For an example, check out this great animated toggle that can be achieved using lottie by airbnb.

So the two drawables that I will use are a full heart and a heart outline both in pink, generated using android material icons. Checkout the code for both:

ic_favorite.xml :

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
>
<path
android:fillColor="@color/pink_500"
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"
/>
</vector>

ic_favorite_border.xml :

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
>
<path
android:fillColor="@color/pink_500"
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"
/>
</vector>

Our two drawables look something like this:

Now we need a drawable for the toggle button so it combines both of the above vectors mapped to two states checked and unchecked. We achieve that using a selector in xml. Selector tag helps us associate the drawables with a state.

button_favorite.xml :

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable = "@drawable/ic_favorite"
android:state_checked="true"
/>
<item android:drawable="@drawable/ic_favorite_border"
android:state_checked="false"
/>
</selector>

With our toggle button drawable ready, its time to write code for our toggle button.

<ToggleButton
android:id="@+id/button_favorite"
android:layout_width="160dp"
android:layout_height="160dp"
android:background="@drawable/button_favorite"
android:checked="false"
android:text=""
android:textOff=""
android:textOn=""
/>

Time to see the results.

Well it solves the purpose, but it still lacks a little bling. Let us try to animate the state change using ScaleAnimation.

ScaleAnimation is simply an animation in android that is used to control the scale of an object. We can specify the point to use for the center of scaling.

Checkout the code in Kotlin below:

scaleAnimation = ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, Animation.RELATIVE_TO_SELF, 0.7f, Animation.RELATIVE_TO_SELF, 0.7f)
scaleAnimation?.setDuration(500)
bounceInterpolator = BounceInterpolator()
scaleAnimation?.setInterpolator(bounceInterpolator)

button_favorite.setOnCheckedChangeListener(object:View.OnClickListener, CompoundButton.OnCheckedChangeListener {
override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean) {
p0?.startAnimation(scaleAnimation);
Log.d("fav", "am i here") //To change body of created functions use File | Settings | File Templates.
}

override fun onClick(p0: View?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
});

Now, it looks a little better.

By the way for those of you missing our dear Java, here is the above code in Java.

scaleAnimation = new ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, Animation.RELATIVE_TO_SELF, 0.7f, Animation.RELATIVE_TO_SELF, 0.7f);
scaleAnimation.setDuration(500);
bounceInterpolator = new BounceInterpolator();
scaleAnimation.setInterpolator(bounceInterpolator);
buttonFavorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
//animation
compoundButton.startAnimation(scaleAnimation);
});

That is it for this post, if you like reading about Android UI and UX design, don’t forget to follow me and hit recommend by clicking the heart. No, not the heart above, the heart below!