Android Native - Modify button appearance using State List Resources

dimitrilc 2 Tallied Votes 105 Views Share

Introduction

Rather than modifying the button widget’s appearance in code, it is possible to do this in an XML resource instead. In this tutorial, we will learn how to create two different types of specialized XML resource files for changing the Drawable and the color.

Goals

At the end of the tutorial, you would have learned:

  1. How to use a Color State List resource.
  2. How to use a Drawable State List resource.

Tools Required

  1. Android Studio. The version used in this tutorial is Android Studio Chipmunk 2021.2.1.

Prerequisite Knowledge

  1. Basic Android.

Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.

  2. Add the vector resource below as ic_baseline_arrow_24.xml into drawable.

     <vector android:height="24dp" android:tint="#000000"
        android:viewportHeight="24" android:viewportWidth="24"
        android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
        <path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
     </vector>
  3. Replace the code inside of activity_main.xml with the code below. The screen will now contain a single ImageButton for us to play with.

     <?xml version="1.0" encoding="utf-8"?>
     <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <ImageButton
            android:id="@+id/imageButton"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:backgroundTint="#00FFFFFF"
            android:scaleType="fitCenter"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_baseline_play_arrow_24" />
     </androidx.constraintlayout.widget.ConstraintLayout>
  4. If we run the app now, it should look like the screenshot below.

Screenshot_2022-05-13_211656.png

Creating a Color State List Resource

Conceptually, a state list resource is an XML file that tells Android what to do when a widget is in a certain state. For Button-type widgets, the common states are focused, pressed, and none.

Let us create the XML file first and dissect the syntax later.

  1. Right-click on res -> New -> Android Resource File.

  2. Select the *Resource type as Color. The root element must be selector. Finally use color as the Directory name**.
    image2.png

  3. Copy and paste the code below into the button_colors.xml file.

     <?xml version="1.0" encoding="utf-8"?>
     <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/purple_700"
            android:state_pressed="true"/>
        <item android:color="@color/purple_700"
            android:state_focused="true" />
        <item android:color="@color/black" />
     </selector>
  4. Now that we have a resource file, it is time to discuss the syntax. There are only a couple of simple rules.
    a. The root element of a state list resource file must be <selector>.
    b. Every child item is an <item>.
    c. Every <item> must have an android:color attribute.
    d. The android:state_X attributes define whether you want this color to be active when the button is in a specific state. e. Here, we configure for purple_700 to be active when the button is either in the focused or pressed states. When it is not focused or pressed, it takes on the color black.

To apply these color states to our Play button, we can add an app:tint attribute directly to the ImageButton widget in the activity_main.xml. The value for this attribute is the path to the color state list button_colors.xml.

app:tint="@color/button_colors"

If we run the app and test the button, it should change its color on click.

Button_Color_States.gif

Modify Button Drawables using a State List

Besides a Color State List, Android provides of state list that is called Drawable State List. The concept is very similar to the Color State List. You define an XML resource that tells Android which Drawable to use for the widget.

  1. To create a Drawable state list, follow the steps above to create an XML resource, but select Drawable as the Resource type instead. The root element remains <selector>. The directory name should be drawable.
    image3.png

  2. Add another vector resource called ic_baseline_pause_24.xml for this step.

     <vector android:height="24dp" android:tint="#000000"
        android:viewportHeight="24" android:viewportWidth="24"
        android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
        <path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
     </vector>
  3. Replace the content of button_drawables.xml with the code below. This will load the vector image created previously when the button is pressed.

     <?xml version="1.0" encoding="utf-8"?>
     <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/ic_baseline_pause_24"
            android:state_pressed="true" />
        <item android:drawable="@drawable/ic_baseline_play_arrow_24" />
     </selector>
  4. Back in activity_main.xml, replace the value of app:srcCompat to reference the new Drawable State List instead of the direct vector image.

     app:srcCompat="@drawable/button_drawables"

If we run the app now, we can see that both the color and Drawable are changed when the button is pressed.

Button_Drawable_States.gif

Solution Code

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <ImageButton
       android:id="@+id/imageButton"
       android:layout_width="200dp"
       android:layout_height="200dp"
       android:backgroundTint="#00FFFFFF"
       android:scaleType="fitCenter"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       app:srcCompat="@drawable/button_drawables"
       app:tint="@color/button_colors" />
</androidx.constraintlayout.widget.ConstraintLayout>

button_drawables.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:drawable="@drawable/ic_baseline_pause_24"
       android:state_pressed="true" />
   <item android:drawable="@drawable/ic_baseline_play_arrow_24" />
</selector>

button_colors.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:color="@color/purple_700"
       android:state_pressed="true"/>
   <item android:color="@color/purple_700"
       android:state_focused="true" />
   <item android:color="@color/black" />
</selector>

ic_baseline_pause_24.xml

<vector android:height="24dp" android:tint="#000000"
   android:viewportHeight="24" android:viewportWidth="24"
   android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

ic_baseline_play_arrow_24

<vector android:height="24dp" android:tint="#000000"
   android:viewportHeight="24" android:viewportWidth="24"
   android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
</vector>

Summary

We have learned how to change button color and drawables using state lists in this tutorial. The full project code can be found at https://github.com/dmitrilc/DaniwebModifyButtonColorUsingColorStateListResource.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.