Navigation and Focus
  • 19 Dec 2023
  • 3 Minutes to read
  • Contributors
  • Dark
    Light

Navigation and Focus

  • Dark
    Light

Article Summary

Overview

To allow this to work, you must manually enable focus on the UI elements you wish to be reached by navigation. You must also control the focus order. These are accomplished using standard Android mechanisms that are summarized here for convenience.


Making UI Elements Focusable

The easiest way to make the UI easily navigated with the buttons and touchpad is to explicitly define the focus rules in the layout XML.

All UI elements including layouts should explicitly define android:focusable and android:focusableInTouchMode

<Button 
	android:id="@+id/firstButton" 
	android:focusable="true" 
	android:focusableInTouchMode="true" 
	android:text="Sample Button"
/>

If these are set true, the system will allow them to become focused. If you have an element, such as a layout or textview, that should never become focused, explicitly set them to false.


Default Focus

The system will give focus to a UI element when the activity starts. To make your application predictable and consistent, you should explicitly request a single UI element request the default focus. You can do this in the layout XML, or in java code.


Default Focus in XML Layout

To request focus in XML we need to add the empty XML element "requestFocus" nested within one of the UI elements.

Most of the layout is controlled by XML attributes and developers normally use self-closing tags. To modify an element to request focus you will need to explicitly add an end tag, and nest the requestFocus within it. The button example below is modified to request focus as:

<Button 
	android:id="@+id/firstButton" 
	android:focusable="true" 
	android:focusableInTouchMode="true" 
	android:text="Sample Button"
>
 <!-- Notice the Button element that requests focus is not self-closing so it can contain an element --> 
	<requestFocus /> 
</Button>


Default Focus in Java Code

You can also easily request focus of any UI element in your onCreate() method.

@Override protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState); 
	setContentView(R.layout.activity_main); 
	Button sampleButton = (Button) findViewById(R.id.firstButton); 
	// It is a best practice to explicitly request focus to a specific UI 
	// element to make navigation with the buttons more consistent to the 
	user 
	sampleButton.requestFocusFromTouch(); 
}

This makes the request to grab the focus as soon as the Activity is created.


Controlling Focus Order

Since the buttons are used to change focus between items, you may want to explicitly control the focus order. There are two ways to do this. You can specify this in the XML, or you can use java code.


Controlling Focus Order in the Layout XML

The XML attributes can define the focus order used to highlight buttons and views within the screen.

The navigation buttons send left and right, so set the android:nextFocusLeft and android:nextFocusRight to valid elements.

<Button
android:id="@+id/firstButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/thirdButton"
	android:nextFocusRight="@+id/secondButton"
	android:text="Sample Button"
/>
<Button android:id="@+id/secondButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/firstButton"
	android:nextFocusRight="@+id/thirdButton"
	android:text="Second Button"
/>
<Button android:id="@+id/thirdButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/secondButton"
	android:nextFocusRight="@+id/firstButton"
	android:text="Third Button"
/>

This example creates circular behavior where you can go to the right or left around all the buttons. Going right from the thirdButton returns to the firstButton. The opposite direction works as well.

You can also make a dead-end so you do not circle around by having elements point to themselves as the next focus. This is the same example without wrapping:

<Button android:id="@+id/firstButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/firstButton"
	android:nextFocusRight="@+id/secondButton"
	android:text="Sample Button"
/>
<Button android:id="@+id/secondButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/firstButton"
	android:nextFocusRight="@+id/thirdButton"
	android:text="Second Button"
/>
<Button android:id="@+id/thirdButton"
	android:focusable="true"
	android:focusableInTouchMode="true"
	android:nextFocusLeft="@+id/secondButton"
	android:nextFocusRight="@+id/thirdButton"
	android:text="Third Button"
/>

In this case, going left from firstButton stays on firstButton. Going right from thirdButton stays on thirdButton.

Combining these gives you complete control over the behavior of the buttons entirely within the XML. The downside to this is it is quite cumbersome to insert new UI elements.


Controlling Focus Order in Java

To override the order in which UI components receive focus, you can override ViewGroup.focusSearch(View focused, int direction). This method takes two parameters, the current view that has focus and the direction in which to move focus to. You can implement whatever rules you want to return a specific view that will receive focus next based on the current focus and direction. As a fallback, you should always return super.focusSearch(focused, direction) if you choose not to return a specific view.


Downloadable Sample

A sample project for Android Studio can be downloaded here.


Summary

By explicitly setting each UI element to be focusable or not, defining a default item to have focus, and controlling the focus order, the developer can create a highly usable interface to work with the physical buttons or the touchpad.


Was this article helpful?