14 min read

Android User Interface Development: Beginner’s Guide

Android User Interface Development: Beginner's Guide

Quickly design and develop compelling user interfaces for your Android applications     

Dealing with undesirable input

Often applications require specific types of input from their users. An application captures input from its user in order for the user to tell it something about the world. This could be anything, from what the user is looking for (that is, a search term), to something about the users themselves (that is, their age). In most of these cases, the users can be guided in the way they give the input using mechanisms, such as an auto-completion box. However, if a user can give you “undesirable” input, then somewhere along the line one of them will.

Undesirable input can be anything ranging from text where a number is expected, through to a search term that yields no results. In both cases, you need to do three things:

  1. Inform the user about the format you expect the data to be in
  2. Let them know that they entered undesirable data
  3. Let them re-enter the data

Correctly labeling input

Your first defense against undesirable input from your users is to correctly label of an input widget. This doesn’t just mean, having a label that reads as follows:

Date of Birth (dd/mm/yy):


It means using the correct widget to capture the data. Your input widgets are a form of a label, they indicate to the user what sort of data you expect them to enter. In many cases, they can be used to stop the user from entering invalid data, or at least make it less likely.

Keep in mind the way that users expect things to work, and that they expect to be able to select things quickly. If you need them to give your application the name of a country, don’t use a Spinner and force them to scroll through a seemingly endless list of names.

Signaling undesirable input

If the user does enter something unwanted or useless, you need to tell them, and fast! The sooner you let the user know that they’ve given you something useless, the sooner they can correct it and get back to using your application.

A common mistake is to simply Toast the user when they press a Save or Submit button. While this is okay if you can only determine their mistake at that point, but you can almost always figure it out beforehand.

Bear in mind that on a touchscreen device, while you have a “focused” widget, it doesn’t play the same role as on a desktop system, and the user isn’t going to “tab” off the widget. This means that as far as possible, your user interface should respond live to the user’s actions, not wait for them to do something else (that is, select another widget) before giving them some feedback. If they do something that makes another form element invalid to use, disable it. If they do something that makes a group of widgets invalid, hide the entire group from them or put it on a different screen.

Android User Interface Development: Validating and Handling Input Data

Coloring and icons are both great ways to quickly tell the user they’ve got something wrong. You can take the additional step of disabling any sort of Save, Next, or Submit button when you realize that some of the user’s input is wrong. However, if you do disable such a button, ensure that it is clear which form element has undesirable data on it, and make sure it is on their screen. A great alternative is to Toast the user when they select a Next button, and scroll to the invalid element.

Make use of background (or asynchronous) messages if you need to check the users’ input against some remote service. This will allow you to validate the user’s content as they are using the application. It’ll also allow you to signal that something is wrong without stopping them from using the rest of the form. They can always come back to the invalid field and correct it.

Recovering from undesirable input

Always ensure that fixing a mistake is as painless as possible for the user. The more work they have to do to correct a misspelled word (or similar), the more likely it is that they will stop using the application. The easiest way to recover from undesirable input (which happens to fit nicely with the above comments) is to tell the user about it before they have a chance to move to another part of the process. However, this isn’t always possible.

There are times when you need to pop up a Please Wait dialog during a process that will (generally as a side effect) validate the users input. In these cases, it’s wise to use a ProgressDialog so you don’t move the user away from your current Activity during this phase. This will have two important side effects:

  • You don’t add unnecessary layers to the activity stack
  • The input the user gave is still available when you close the ProgressDialog

Giving users direct feedback

When accepting text or other keyboard input from the users, it’s best to signal its validity to the users while they are still entering it. A common method is to use an ImageView to the right of the EditText widget, and changing the image content to signal whether the user has entered valid or invalid content. The image displayed in the ImageView can be set, based on whether the input is currently valid or not. This gives the user a live view of the validation process. This mechanism also works well for signaling variable levels of validation (that is, when the input is not strictly valid or invalid, but rather good quality or undesirable quality), such as in the case of a password input.

You can either make use of image icons, or simply use an Android drawable XML resource to represent the validity (that is, green for valid, red for invalid). This also means that your icon will scale to any size that you prescribe to it in your layout XML file.

Colors and icons
It’s often a good idea to use a non-color indicator to differentiate icons. Someone who is color blind may find it difficult or impossible to tell the difference between two icons unless you change the shape as well as the color. Having your “valid” icon as a green circle, and your “invalid” icon as a red hexagon will make your application more usable.

In order to avoid cluttering your screen with icons, you may want to display only the validation icon next to the field the user is currently working with. It’s a good idea however, to make use of the INVISIBLE View state instead of GONE in order to avoid changing the layout when the user changes the focus of the user interface. At the same time, please ensure that validation icons are the same size.

Avoiding invalid input entirely

Remember that with a mobile device, time is often a constraint for the user. For this reason (and for simple usability reasons) you should generally strive to avoid invalid input from your users entirely. Android provides you with several mechanisms with which to do this, and it’s wise to make use of them at every opportunity. Generally, you will want to make use of widgets that avoid validation requirements. This is almost always an option in Android, and even when your requirements are more complex than simple type information, you can generally customize the widget to stop the user from breaking your validation rules.

Capturing date and time

As we’ve already discussed, when inputting date and time you should make use of DatePicker and TimePicker widgets, or the DatePickerDialog and TimePickerDialog to avoid the layout issues that the primitive widgets introduce.

Avoid creating your own calendar widget unless it’s a hard requirement of your application. You may not like how a DatePickerDialog looks, but users have seen them in other Android applications and know how to use them. It’s also possible that these standard widgets are improved in future Android releases, giving your application an improvement with no work from your side.

Android User Interface Development: Validating and Handling Input Data

You may find that you need additional validation for date and time inputs, especially when capturing date or time ranges. For example, if you ask a user for a date of birth, the user shouldn’t be able to enter a field that indicates any time later than “today” (unless it’s an expected date of birth). While the DatePicker class has an event listener which allows you to listen for changes to its data (and DatePickerDialog implements this event listener), you cannot use this event listener to cancel the change event.

Therefore, in order to Cancel the event, you need to change the input back to something valid while the event is executing. This is a surprisingly simple trick in Android. Since the events are executed on the same thread that does the painting, it allows you to change the value before the invalid data is rendered on the screen. The following is a simple example of a ValidatingDatePickerDialog which you can use in order to implement a simple level of date validation in your application. Another such class could be easily written for TimePickerDialog if you needed one.

public class ValidatingDatePickerDialog extends DatePickerDialog {
private int lastValidYear;
private int lastValidMonth;
private int lastValidDay;
private ValidationCallback callback = null;
public ValidatingDatePickerDialog(
final Context context,
final OnDateSetListener callBack,
final int year,
final int monthOfYear,
final int dayOfMonth) {
super(context, callBack, year, monthOfYear, dayOfMonth);
setValidData(year, monthOfYear, dayOfMonth);
}
protected void setValidData(
final int year,
final int monthOfYear,
final int dayOfMonth) {
lastValidYear = year;
lastValidMonth = monthOfYear;
lastValidDay = dayOfMonth;
}
@Override
public void onDateChanged(
final DatePicker view,
final int year,
final int month,
final int day) {
if(callback != null && !callback.isValid(year, month, day)) {
view.updateDate(
lastValidYear,
lastValidMonth,
lastValidDay);
} else {
super.onDateChanged(view, year, month, day);
setValidData(year, month, day);
}
}
public void setValidationCallback(
final ValidationCallback callback) {
this.callback = callback;
}
public ValidationCallback getValidationCallback() {
return callback;
}
public interface ValidationCallback {
boolean isValid(int year, int monthOfYear, int dayOfMonth);
}
}


This method of handling validation can be used in most Android widgets that don’t offer implicit validation of their events, and it offers a much better user experience than giving the user a Toast with the text Please enter a valid date of birth. It also avoids the need for additional layers of validation in your application.

Using spinners and ListView for selection

There are many times when the user needs to select something from a list of possible values in an application. However, they offer several features that can be very useful when it comes to validation. They are implicitly validated widgets, that is, it’s impossible for the user to enter incorrect data since the possible values for input are defined by the application. However, what about when the set of valid items changes based on other user input, or some external source of information? In these cases, several options are available to you.

Changing the data set

The simplest method of stopping the user from selecting a value that is no longer valid is to remove it from the data set. Modifying the data set of an AdapterView is a good idea because it “takes the option off the menu”. However, it doesn’t work well with the Spinner class, since, if the item is removed off the screen, the user will be left wondering what happened to the item that was there just a second ago (and may be concerned that they are going mad).

In order not to confuse or frustrate your users, you should only remove items from a Spinner or ListView data set if the item will probably not be added back into the data set. A good example of this requirement is a list of Wi-Fi networks available, or Bluetooth devices within range. In both of these cases, the list of available items is defined by the environment. The user will accept that the displayed options are not always going to be available to them, and new items may appear from time to time.

Disabling selections

An alternative and usually more user-friendly method of stopping certain items from being selected is to disable them. You can make the ListView or Spinner ignore items by overriding the isEnabled(int) method in the ListAdapter class. However, this method will only disable the item at the event level, the item will still appear as enabled (it’s primary purpose is to define separator views).

In order to visually disable an item, you’ll need to disable the View that the item is displayed in. This is a very effective way of telling the user, “You’ve changed something that has made this item unavailable”. Graphically disabling an item also lets the user know that it may become available in the future.

Capturing text input

The most difficult inputs to work with are the various forms of text input. I find that working with a soft keyboard may not be as quick as working with a hardware keyboard, but from a development point of view it offers something that a hardware keyboard does not—flexibility. When I want to enter text into a field, a soft keyboard’s state will indicate the type of input that is valid for that field. If I’m supposed to enter a phone number, the keyboard can display only numbers, or even change into a dial pad. This not only indicates to me what I’m supposed to do, but also stops me from inputting anything that would cause a validation error.

The Android TextView (and thus the EditText) widgets provide you with a host of different options and methods by which you can define complex validation rules for text input. Many of these options are also understood by various soft keyboards, allowing them to display subsets of the full keyboard based on how the TextView widget has been configured. Even if not fully understood by the soft keyboard (or if a hardware keyboard is in use), the rules of the specified option must be adhered to. The easiest way to tell the EditText what type of data you want it to capture is with the inputType XML attribute.

As you’ll see from the inputType documentation, all of its possible values are different combinations of the bit masks available in the android.view.inputmethod.InputType interface. The options available as values to the inputType attribute will cover most cases where you need to capture a specific type of input. You can also create your own, more complex input types by using the TextView.setRawInput or TextView. setKeyboardListener methods.

Keyboard listeners As far as possible, you should either use the input type or a standard KeyListener to handle your text validation. Writing a KeyListener is a non-trivial task, and in some cases may see you implementing a custom soft keyboard. A KeyListener in Android, which defines an input type other than TYPE_NULL, may not have its listener events (onKeyDown, onKeyUp, and onKeyOther) invoked at all if a soft keyboard is present. The key events of a KeyListener are only used to accept or reject events from a hardware keyboard. Software keyboards use the input type attribute of a TextView to decide what functionality they should provide to the user.

Autocompleting text input

The Spinner and ListView widgets are great ways to ask your user to select from a predefined list of options. However, both have a major flaw in that they don’t scale well to very long lists. While the implementation and performance are both very good, users just don’t like looking through massive lists of data. The standard way to solve this problem is to provide an auto completed text input widget.

Android User Interface Development: Validating and Handling Input Data

Autocompleted input widgets are also often used with a history of past options that the user has given, or to suggest possible ways the user may want to “complete” their input. The Android AutoCompleteTextView widget is an EditText with autocompletion capabilities. It uses a ListAdapter (which must also implement the Filterable interface) to find and display the list of possible suggestions to the user.

However, an AutoCompleteTextView has two major flaws:

  • It’s still a TextView and the user is not forced to select one of the suggested items, this means that its content must be validated separately.
  • The suggestion list is displayed directly below the widget, consuming a fair amount of screen space. Combined with a soft keyboard for input, the user interface may become cluttered or almost unusable on a small screen

Both of these issues can be solved by using the AutoCompleteTextView class carefully and sparingly. They are brilliantly useful when you need a search box, URL input, or something similar but they are often not suitable for placing in the middle of the screen (they are best placed at the top where they have plenty of space for the suggestion list).

LEAVE A REPLY

Please enter your comment!
Please enter your name here