Customising an Android Button

The stock android button can look a little dull and basic, so today I’m going to look at making a custom button.
Start with a generic android project (my target is 16, min version 7 – this will cause Eclipse to include the android-support-v4.jar which is needed for some of the xml statements in this tutorial) and navigate to your res/layout/yourlayout.xml layout xml. If you are using the a similar setup to me, this will already be open. If you want to use the graphical layout you might need to close and re-open your layout xml, but in this tutorial I am going to edit the xml directly, as this should help reinforce the connection between the Android Button API and the statements in your xml files.
If we add a basic button to the relative layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn_text_reg" />

</RelativeLayout>

we get something that looks like this:
Plain Android Button Image
To learn how to spruce it up I followed the API Buttons guide.
What I’m going to do in this tutorial is create a style resource that will include a state list. The style resource is like a CSS class, I can define a style once and apply it to multiple buttons. The state list applies different rules depending on whether the button is inactive, pressed, hovered etc. In this case, the state list will change the background colour. The order of things is this, the Style requires a State List, the State List requires different drawables for different states. So we will start with the drawables and work our way back to the Styles (which will be referenced in our main layout xml).

Defining Drawable for 2 states

Let’s create the two drawables. If you don’t have a res/drawable folder you will need to create one. Using the Android XML wizard, I’m going to call my first xml file btn_active.xml, and select shape as the root element. I want a button with rounded corners, some padding around the text and a black outline. See the following XML (note I have some predefined ‘colors‘):

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <corners 
        android:radius="15dp"/>
    <!-- Padding, in this case, around the button's text  -->
    <padding
        android:left="20dp"
        android:right="20dp"
        android:top="10dp"
        android:bottom="10dp"
        />
    <solid 
        android:color="@color/active_orange"/>
    <stroke
        android:color="@color/btn_black"
        android:width="2dp" />
</shape>

I then create another xml file called btn_inactive.xml, which is the same as the above with a different colour specified in the solid statement (white).

Creating the State List XML

Now we have defined our 2 states, let’s add them to a state list xml file.
Again, using the XML wizard, create a new xml file called states.xml (any name is OK, it lives in the res/drawable folder) and select the root element as selector. The way the states are listed, the last item will be the default state for any state which has not been specified before it (higher up the list). In this example, if the button is pressed/hovered/focussed the btn_active.xml will be used, otherwise the btn_inactive.xml will be used.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" 
    android:enterFadeDuration="200" 
    android:exitFadeDuration="200">

    <item android:drawable="@drawable/btn_active" android:state_pressed="true"/>
    <item android:drawable="@drawable/btn_active" android:state_focused="true"/>
    <item android:drawable="@drawable/btn_active" android:state_hovered="true"/>
    <item android:drawable="@drawable/btn_inactive"/>

</selector>

Creating the style XML

We are creating a lot of xml here, states, state lists, colors, dimens and so on, but the final xml file we create helps put all these elements under one roof and will lead to a much simpler, readable and maintainable layout for this demo activity.
With the vanilla button earlier on I put some statements into the button definition (fill width and wrap height to button content). If we were to add to this for each button used across an app, we could easily end up repeating code rather than re-using code. Let’s define our style XML – if you don’t already have one, create a styles.xml in your res/values folder, but this should be created by Eclipse as part of a new project:

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This is created by Eclipse -->
    <style name="AppTheme" parent="android:Theme.Light" />
    <!-- This is created by us -->
    <style name="CustomButton">
        <item name="android:layout_width">200dp</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_gravity">center_horizontal</item>
        <item name="android:layout_marginTop">@dimen/10dp</item>
        <item name="android:background">@drawable/states</item>
    </style>

</resources>

Applying the style in the layout

I have changed the main layout xml from a RelativeLayout to a LinearLayout. Here it is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn_text_reg" />

    <Button
        android:id="@+id/my_btn_01"
        style="@style/CustomButton"
        android:text="@string/btn_text_custom" />

    <Button
        android:id="@+id/my_btn_02"
        style="@style/CustomButton"
        android:text="@string/btn_text_custom" />

</LinearLayout>

Now if we compile the app and run it, we should have something like the following (the second custom button is in the pressed state):
Custom Android Button

If you have Android 2.1 or greater and want to try it out, you can download the APK here, remember to allow non-market apps in your settings.