Advertisement
  1. Code
  2. Mobile Development
  3. Android Development

Android User Interface Design: The Basics of Control Focus Order

Scroll to top
This post is part of a series called Android User Interface Design.
Android User Interface Design: Password Confirmation
Android User Interface Design: Radio Buttons

There’s nothing more annoying than trying to navigate a poorly designed user interface on a mobile application. How your application behaves in terms of screen navigation can mean the difference between a happy user and one who flames you on the Android Market. Today, we focus on focus—that is: control focus, and how to customize it within your user interfaces.

Android device input methods are becoming quite diverse: directional pads, trackballs, touch screens, keyboards, and more. Some devices, like tablets, are primarily navigated by touch. Others, like the Google TV, have no touch screen whatsoever and rely upon input devices such as those with a directional pad (d-pad).

Android developers need to understand how users navigate the controls on a screen, how and in what order these screen controls gain and lose focus, and how to customize control focus order to their applications to provide users with a frustration-free experience.

Understanding Control Focus Order

The Android platform does its best to determine an appropriate control order for a given layout type. In many cases, the default focus order makes sense. However, this is not always the case. Which control should gain focus next is determined by finding the current focused control’s nearest neighbor in a given direction (up/down/left/right). When there are multiple controls that fit that description, the platform scans from left to right, top to bottom, much like one might read a book in English.

This has some ramifications. By default, the top-most control in a screen would have nothing to focus on if the user navigated “Up”, nor would anything happen if the user navigated “Down” from the bottom control on the screen. Similarly, nothing would occur if the user tried to navigate “Left” from the left-most control, or “Right” from the right-most control. There is no “wrapping” of focus, by default.

Now let’s look at an example of how you might want to modify the default focus behavior on a screen and make it work for you and your users. For example, let’s say you want to force your focus order to wrap circularly around a set of controls that make up a clock face.

Step 0: Getting Started

We provide the full source code for the sample application discussed in this tutorial. You can download the sample source code we provide for review here.

Step 1: Define a Layout with Controls

First, create or edit the layout resource file used by your Activity class, such as /res/layout/main.xml. For example, the following layout defines a sort of “clock face” of Button controls using a RelativeLayout.

1
2
<?xml version="1.0" encoding="utf-8"?>
3
<RelativeLayout
4
    xmlns:android="http://schemas.android.com/apk/res/android"
5
    android:layout_width="fill_parent"
6
    android:layout_height="fill_parent">
7
    <Button
8
        style="@style/clockFaceNum"
9
        android:text="12"
10
        android:id="@+id/button12"
11
        android:layout_alignParentTop="true"
12
        android:layout_centerHorizontal="true">
13
    </Button>
14
    <Button
15
        style="@style/clockFaceNum"
16
        android:text="11"
17
        android:id="@+id/button11"
18
        android:layout_below="@+id/button12"
19
        android:layout_toLeftOf="@+id/button12">
20
    </Button>
21
    <Button
22
        style="@style/clockFaceNum"
23
        android:text="1"
24
        android:id="@+id/button1"
25
        android:layout_below="@+id/button12"
26
        android:layout_toRightOf="@+id/button12">
27
    </Button>
28
    <Button
29
        style="@style/clockFaceNum"
30
        android:text="10"
31
        android:id="@+id/button10"
32
        android:layout_below="@+id/button11"
33
        android:layout_toLeftOf="@+id/button11">
34
    </Button>
35
    <Button
36
        style="@style/clockFaceNum"
37
        android:text="2"
38
        android:id="@+id/button2"
39
        android:layout_below="@+id/button1"
40
        android:layout_toRightOf="@+id/button1">
41
    </Button>
42
    <Button
43
        style="@style/clockFaceNum"
44
        android:text="9"
45
        android:id="@+id/button9"
46
        android:layout_below="@+id/button10"
47
        android:layout_toLeftOf="@+id/button10">
48
    </Button>
49
50
    <Button
51
        style="@style/clockFaceNum"
52
        android:text="3"
53
        android:id="@+id/button3"
54
        android:layout_below="@+id/button2"
55
        android:layout_toRightOf="@+id/button2">
56
    </Button>
57
    <Button
58
        style="@style/clockFaceNum"
59
        android:text="8"
60
        android:id="@+id/button8"
61
        android:layout_below="@+id/button9"
62
        android:layout_toRightOf="@+id/button9">
63
    </Button>
64
    <Button
65
        style="@style/clockFaceNum"
66
        android:text="4"
67
        android:id="@+id/button4"
68
        android:layout_below="@+id/button3"
69
        android:layout_toLeftOf="@+id/button3">
70
    </Button>
71
    <Button
72
        style="@style/clockFaceNum"
73
        android:text="7"
74
        android:id="@+id/button7"
75
        android:layout_below="@+id/button8"
76
        android:layout_toRightOf="@+id/button8">
77
    </Button>
78
    <Button
79
        style="@style/clockFaceNum"
80
        android:text="5"
81
        android:id="@+id/button5"
82
        android:layout_below="@+id/button4"
83
        android:layout_toLeftOf="@+id/button4">
84
    </Button>
85
    <Button
86
        style="@style/clockFaceNum"
87
        android:text="6"
88
        android:id="@+id/button6"
89
        android:layout_below="@+id/button5"
90
        android:layout_centerHorizontal="true">
91
    </Button>
92
</RelativeLayout>

The style called clockFaceNum is defined in the /res/values/styles.xml file as follows:

1
2
<?xml version="1.0" encoding="utf-8"?>
3
<resources>
4
    <style
5
        name="clockFaceNum">
6
        <item
7
            name="android:layout_width">38dp</item>
8
        <item
9
            name="android:layout_height">38dp</item>
10
        <item
11
            name="android:onClick">numClicked</item>
12
        <item
13
            name="android:textSize">9sp</item>
14
    </style>
15
</resources>

The resulting screen looks like this:

Screen showing 12 buttonsScreen showing 12 buttonsScreen showing 12 buttons

Step 2: Review the Default Focus Order

Let’s review the default focus order for the clock face Button controls in this RelativeLayout. If the user is focused on the 12 button and presses “down” on a directional pad, the next control to take focus will be the 11 Button, followed by the 10 Button, etc.

The default “Down” path is shown here:

Screen showing the default, and unintuitive d-pad focus changeScreen showing the default, and unintuitive d-pad focus changeScreen showing the default, and unintuitive d-pad focus change

Step 3: Provide a Custom Control Focus Order

Let’s say we want to force the user to only be able to traverse the clock face controls in clockwise or counterclockwise order as opposed to the default focus order, as shown:

Screen showing 12 buttons and the circular path we'd likeScreen showing 12 buttons and the circular path we'd likeScreen showing 12 buttons and the circular path we'd like

We can define this behavior by specifying, for each Button, which control should gain focus next. There are four XML attributes you can set on any View control to define the focus order. These attributes are:

  • android:nextFocusUp-This attribute defines the control that should gain focus if the user navigates up
  • android:nextFocusDown-This attribute defines the control that should gain focus if the user navigates down
  • android:nextFocusLeft-This attribute defines the control that should gain focus if the user navigates left
  • android:nextFocusRight-This attribute defines the control that should gain focus if the user navigates right

So let’s say we want all “Down” and “Right” navigation to allow the user in traverse the clock face Button controls in clockwise order, and all “Up” and “Left” navigation to allow the user to traverse the controls in counter-clockwise order. We would then have to define these four attributes for each control. For example, if you moved “Down” or “Right” from the 12 Button, you would reach the 1 Button. Similarly, if you moved “Up” or “Left” from the 12 Button, you would reach the 11 Button.

A complete definition of this new clock face layout looks like this:

1
2
<?xml version="1.0" encoding="utf-8"?>
3
<RelativeLayout
4
    xmlns:android="http://schemas.android.com/apk/res/android"
5
    android:layout_width="fill_parent"
6
    android:layout_height="fill_parent">
7
    <Button
8
        style="@style/clockFaceNum"
9
        android:text="12"
10
        android:id="@+id/button12"
11
        android:layout_alignParentTop="true"
12
        android:layout_centerHorizontal="true"
13
        android:nextFocusUp="@+id/button11"
14
        android:nextFocusLeft="@+id/button11"
15
        android:nextFocusRight="@+id/button1"
16
        android:nextFocusDown="@+id/button1">
17
    </Button>
18
    <Button
19
        style="@style/clockFaceNum"
20
        android:text="11"
21
        android:id="@+id/button11"
22
        android:layout_below="@+id/button12"
23
        android:layout_toLeftOf="@+id/button12"
24
        android:nextFocusUp="@+id/button10"
25
        android:nextFocusLeft="@+id/button10"
26
        android:nextFocusRight="@+id/button12"
27
        android:nextFocusDown="@+id/button12">
28
    </Button>
29
    <Button
30
        style="@style/clockFaceNum"
31
        android:text="1"
32
        android:id="@+id/button1"
33
        android:layout_below="@+id/button12"
34
        android:layout_toRightOf="@+id/button12"
35
        android:nextFocusUp="@+id/button12"
36
        android:nextFocusLeft="@+id/button12"
37
        android:nextFocusRight="@+id/button2"
38
        android:nextFocusDown="@+id/button2">
39
    </Button>
40
    <Button
41
        style="@style/clockFaceNum"
42
        android:text="10"
43
        android:id="@+id/button10"
44
        android:layout_below="@+id/button11"
45
        android:layout_toLeftOf="@+id/button11"
46
        android:nextFocusUp="@+id/button9"
47
        android:nextFocusLeft="@+id/button9"
48
        android:nextFocusRight="@+id/button11"
49
        android:nextFocusDown="@+id/button11">
50
    </Button>
51
    <Button
52
        style="@style/clockFaceNum"
53
        android:text="2"
54
        android:id="@+id/button2"
55
        android:layout_below="@+id/button1"
56
        android:layout_toRightOf="@+id/button1"
57
        android:nextFocusUp="@+id/button1"
58
        android:nextFocusLeft="@+id/button1"
59
        android:nextFocusRight="@+id/button3"
60
        android:nextFocusDown="@+id/button3">
61
    </Button>
62
    <Button
63
        style="@style/clockFaceNum"
64
        android:text="9"
65
        android:id="@+id/button9"
66
        android:layout_below="@+id/button10"
67
        android:layout_toLeftOf="@+id/button10"
68
        android:nextFocusUp="@+id/button8"
69
        android:nextFocusLeft="@+id/button8"
70
        android:nextFocusRight="@+id/button10"
71
        android:nextFocusDown="@+id/button10">
72
    </Button>
73
74
    <Button
75
        style="@style/clockFaceNum"
76
        android:text="3"
77
        android:id="@+id/button3"
78
        android:layout_below="@+id/button2"
79
        android:layout_toRightOf="@+id/button2"
80
        android:nextFocusUp="@+id/button2"
81
        android:nextFocusLeft="@+id/button2"
82
        android:nextFocusRight="@+id/button4"
83
        android:nextFocusDown="@+id/button4">
84
    </Button>
85
    <Button
86
        style="@style/clockFaceNum"
87
        android:text="8"
88
        android:id="@+id/button8"
89
        android:layout_below="@+id/button9"
90
        android:layout_toRightOf="@+id/button9"
91
        android:nextFocusUp="@+id/button7"
92
        android:nextFocusLeft="@+id/button7"
93
        android:nextFocusRight="@+id/button9"
94
        android:nextFocusDown="@+id/button9">
95
    </Button>
96
    <Button
97
        style="@style/clockFaceNum"
98
        android:text="4"
99
        android:id="@+id/button4"
100
        android:layout_below="@+id/button3"
101
        android:layout_toLeftOf="@+id/button3"
102
        android:nextFocusUp="@+id/button3"
103
        android:nextFocusLeft="@+id/button3"
104
        android:nextFocusRight="@+id/button5"
105
        android:nextFocusDown="@+id/button5">
106
    </Button>
107
    <Button
108
        style="@style/clockFaceNum"
109
        android:text="7"
110
        android:id="@+id/button7"
111
        android:layout_below="@+id/button8"
112
        android:layout_toRightOf="@+id/button8"
113
        android:nextFocusUp="@+id/button6"
114
        android:nextFocusLeft="@+id/button6"
115
        android:nextFocusRight="@+id/button8"
116
        android:nextFocusDown="@+id/button8">
117
    </Button>
118
    <Button
119
        style="@style/clockFaceNum"
120
        android:text="5"
121
        android:id="@+id/button5"
122
        android:layout_below="@+id/button4"
123
        android:layout_toLeftOf="@+id/button4"
124
        android:nextFocusUp="@+id/button4"
125
        android:nextFocusLeft="@+id/button4"
126
        android:nextFocusRight="@+id/button6"
127
        android:nextFocusDown="@+id/button6">
128
    </Button>
129
    <Button
130
        style="@style/clockFaceNum"
131
        android:text="6"
132
        android:id="@+id/button6"
133
        android:layout_below="@+id/button5"
134
        android:layout_centerHorizontal="true"
135
        android:nextFocusUp="@+id/button5"
136
        android:nextFocusLeft="@+id/button5"
137
        android:nextFocusRight="@+id/button7"
138
        android:nextFocusDown="@+id/button7">
139
    </Button>
140
</RelativeLayout>

Therefore, our new “Down” path, starting at the 12 Button, looks like this now:

Screen showing 12 buttons and the new, intuitive pathScreen showing 12 buttons and the new, intuitive pathScreen showing 12 buttons and the new, intuitive path

Step 4: Setting Initial Control Focus

Finally, here’s a trick for setting the default control to gain focus on a given screen from within your layout file. You can only do this for one View control in each file.

Use the tag within the View control to set the initial focus on the screen. For example, we might want to update the 12 Button to gain initial focus, like this:

1
2
    <Button
3
        style="@style/clockFaceNum"
4
        android:text="12"
5
        android:id="@+id/button12"
6
        android:layout_alignParentTop="true"
7
        android:layout_centerHorizontal="true"
8
        android:nextFocusUp="@+id/button11"
9
        android:nextFocusLeft="@+id/button11"
10
        android:nextFocusRight="@+id/button1"
11
        android:nextFocusDown="@+id/button1">
12
        <requestFocus />
13
    </Button>

You can, of course, also use the programmatic method to set the control focus as well, using the View class method called requestFocus().

Conclusion

Android developers need to remember that different users will navigate an application’s user interface using different input methods. Some methods make it easy to jump between screen controls, while others can make navigation onerous. Developers can provide custom focus orders which can greatly improve the user’s experience with the application. Please don't forget about the keyboard users. ☺

About the Authors

Mobile developers Lauren Darcey and Shane Conder have coauthored several books on Android development: an in-depth programming book entitled Android Wireless Application Development, Second Edition and Sams Teach Yourself Android Application Development in 24 Hours, Second Edition. When not writing, they spend their time developing mobile software at their company and providing consulting services. They can be reached at via email to androidwirelessdev+mt@gmail.com, via their blog at androidbook.blogspot.com, and on Twitter @androidwireless.

Need More Help Writing Android Apps? Check out our Latest Books and Resources!

Buy Android Wireless Application Development, 2nd Edition  Buy Sam's Teach Yourself Android Application Development in 24 Hours, Second Edition  Mamlambo code at Code Canyon

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.