Android Application Development Cookbook(Second Edition)
上QQ阅读APP看书,第一时间看更新

Using graphics to show button state

We've talked about the versatility of Android Views and how behavior and visual appearance can be customized. In this recipe, we will create a drawable state selector, which is a resource defined in XML that specifies the drawable to use based on the View's state. The most commonly used states, along with the possible values, include:

  • state_pressed=["true" | "false"]
  • state_focused=["true" | "false"]
  • state_selected=["true" | "false"]
  • state_checked=["true" | "false"]
  • state_enabled=["true" | "false"]

To define a state selector, create an XML file with the <selector> element, as shown:

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

Within the <selector> element, we define an <item> to identify the drawable to be used based on the specified state(s). Here's an example <item> element using multiple states:

<item
    android:drawable="@android:color/darker_gray"
    android:state_checked="true"
    android:state_selected="false"/>
Tip

It's important to remember the file is read from top to bottom so the first item that meets the state requirements will be used. A default drawable, one with no states included, would need to go last.

For this recipe, we will use a state selector to change the background color based on the ToggleButton state.

Getting ready

Create a new project in Android Studio and call it StateSelector using the default Phone & Tablet options. When prompted for the Activity Type, select Empty Activity. To make it easier to type the code for this recipe, we will use a color as the graphic to represent the button state.

How to do it...

We will start by creating the state selector, which is a resource file defined with XML code. We will then set up the button to use our new state selector. Here are the steps:

  1. Create a new XML file in the res/drawable folder and call it: state_selector.xml. The file should consist of the following XML code:
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:drawable="@android:color/darker_gray"
            android:state_checked="true"/>
        <item
            android:drawable="@android:color/white"
            android:state_checked="false"/>
    </selector>
  2. Now open the activity_main.xml file and drop in a ToggleButton as follows:
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New ToggleButton"
        android:id="@+id/toggleButton"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/state_selector" />
  3. Run the application on a device or emulator.

How it works...

The main concept to understand here is the Android State Selector. As shown in Step 2, we created a resource file which specified a drawable (a color in this case) based on state_checked.

Android supports many other state conditions besides checked. While typing in android:state, look at the autocomplete dropdown to see the list of other options.

Once we have the drawable resource created (the XML from step 1), we just have to tell the view to use it. Since we wanted the background color to change based on the state, we use the android:background property.

state_selector.xml is a drawable resource that can be passed to any property that accepts a drawable. We could, for example, replace the button in a checkbox with the following XML:

android:button="@drawable/state_selector"

There's more...

What if we wanted actual images for the graphics instead of just a color change? This is as easy as changing the drawable referenced in the item state.

The source code available for download uses two graphic images, downloaded from: https://pixabay.com/ (this was chosen because the images are free to use and didn't require a login.)

Once you have your desired images, place them in the res/drawable folder. Then, change the state item line in the XML to reference your images. Here's an example:

<item
    android:drawable="@drawable/checked_on"
    android:state_checked="true"/>

(Change check_on to match your image resource name.)

Using designated folders for screen-specific resources

When Android encounters a @drawable reference, it expects to find the target in one of the res/drawable folders. These are designed for different screen densities: ldpi (low dots per inch), mdpi (medium), hdpi (high), and xhdpi (extra-high) and they allow us to create resources for specific target devices. When an application is running on a specific device, Android will load resources from the designated folder that most closely matches the actual screen density.

If it finds this folder empty, it will try the next nearest match and so on until it finds the named resource. For tutorial purposes, a separate set of files for each possible density is not required, and so placing our images in the drawable folder is a simple way to run the exercise on any device.

Tip

For a complete list of resource identifiers available, visit http://developer.android.com/guide/topics/resources/providing-resources.html.

See also

For another example on Android resource selection, see the recipe on Selecting theme based on the OS version later.