Constraints is a design principle in which we limit the actions the user can undertake in order to direct them to the most appropriate action. That seems simple enough. The actual definition of constraint extends to the limits of what the system can do. A mobile device is constrained by it’s physical limitations of screen size/resolution, touch inputs(typically) and the array of sensors that help manage the input. In Android, you are also constrained by the OS and some controls (back/home). So the principle of design constraints is quite large but for our purposes we want to limit the constraints to those that are adjustable by our development. So our specific definition of constraint will be left with, What elements can we constrain within our design to encourage the user to take certain actions?
Thinking about constraints in this manner will make things easier.
The most obvious of these constraints on mobile is to toggle active buttons until the user has entered the correct text or another action is completed. For instance, when a user is entering login information we will need to disable the “login” button until such time as we have checked the username and password against being empty or against whatever screwed up password scheme has been foisted upon you.
Instagram does a good job at disabling the functionality until you have entered your information. But here is the important part, it isn’t good enough that you disable the button in your code but you also have to visually indicate to the user that it is disabled. Color State List provides the easiest way to implement this without any complicated code.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:color="#ffff0000"/> <!-- hidden --> <item android:state_focused="true" android:color="#ff0000ff"/> <!-- focused --> <item android:color="#ff000000"/> <!-- default --> </selector>
This layout XML will apply the color list to a View:
<Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/button_text" android:textColor="@color/button_text" />
Enabling or disabling a button is a good way to constrain the users actions, and restricting those actions is good practice. This also applies to any delayed actions after the button is pressed. On a login page, you may have to verify their credentials with a server and in the meantime you should disable the button until they can act on it. [Hint: Disabling the buttons after they’ve been pressed also prevents the user from mashing away at them because you didn’t implement your Feedback correctly. ]
Dialogs are another method of constraining the users actions to a specific task. They force the users attention to a very narrow task and do a good job of constraining the actions that they can accomplish.
However, I’ve found dialogs are often overused as a crutch for poor architecture or design. Too many developers want to constrain a users actions because they need to handle background tasks. [Hint: Your technical issues are not the users fault. Don’t bother them with it. I’m looking at you working and busy dialogs. ]
Although worthy of it’s own article, dialogs should be used sparingly and with the understanding that you are constraining a users actions regardless of what they were trying to accomplish. Interrupting their current actions for your constraint may not always be the best user experience. (see clippy)
Dialogs can be used effectively if you stick to a couple of heuristics;
- Always stick to the Android convention of Cancel button on the left, Action button on the right. No exceptions.
- Usually, when there is no Action button, there is no Cancel button. That is if your action is in the dialog like selecting from a list there is no need for a Cancel button, the back button should handle that.
- Usually keep your dialogs to a single action. There are cases where you may have a couple actions to complete but try to minimize the number of actions within a dialog.
- Never nest dialogs. Dialogs should not open other dialogs. It’s way too confusing for the user.
- Never interrupt a user when they are in the middle of an action. Dialogs are distracting enough so they should not force an action where the user doesn’t want it.
(This section has a lot more opinion and personal experience in it than previous sections. Take it with a grain of salt)
The principle of Mapping or Natural Mapping relates to how an application controls translate to the appropriate action. In the real world Natural Mapping is usually based on a physical spatial relationship. Take a simple toaster for example. Pressing down the toast lever to make the toast go down. The action of pressing down on the lever translates into the toast (bread technically) going down as well. It’s a Natural Mapping between the physical action of the lever and action of the toast.
If toast comes out, where did the bread go?
On mobile or digital devices the natural mapping is slightly more subtle with its implementation and relies more on convention over spatial relationships. What I mean by convention is that there are a number of assumed relationships that users of those devices will immediately assume without you having to prompt them. And what I mean by that is that there are “Android” ways of doing things and you should do that.
Content will usually scroll top to bottom, forward buttons on the right, back on the left, Menu on the top left hamburger icon. Those conventions are usually platform specific and while they don’t usually correspond to a physical action they are still “natural” motions for the mobile device user.
Mapping conventions are where users expect actions to be. This may not be the same on Android and iOS and as a result your designs should be adapted for your specific platform. You cannot carry one design between two platforms effectively
On Android, those conventions are loosely documented on the Google material design site, mostly in the form of “Best Practices” or layered deep within a component specification. The problem with those cultural conventions is that they really depend on the user. Like any true Scotsman,cultural conventions are dependant upon the user and it doesn’t help that we’ve migrated from different design patterns in Android since 1.0.
Additionally, your user base may be different in how they expect the device to function and their expectations for mapping will differ than others. There is no easy way to determine this and outside of A/B testing with real users there isn’t much you can do.
But A/B testing doesn’t need to be complicated. In the past I’ve pointed a camera at a device and asked the user to talk through their thinking out loud. It is really enlightening to see how users engage with your app and you will be surprised at how your expectations are wildly different from your users. In one situation I was surprised to find that most users will ignore the Toolbar overflow menu almost entirely during testing. The Google Design spec includes it as a component but for our use case we needed to move those features out of the menu because of the results from testing. The Natural Mapping for this user didn’t include the overflow menu and it would be a poor design on our part to include it.
Of course, as any true Android user knows there are a couple of conventions that shouldn’t be violated. Here are a couple of my personal conventions that I have found that most users like to follow. Feel free to comment in below if you have any others.
Let’s talk about Back.
The soft/hard back button is a confusing combination of back navigation and undo. In my opinion, undo should always take priority over back navigation and you should override the OnBackPressed() function for actions initiated by the user. That means if you pull up a dialog, back should close it. A menu drawer, back should close it. Halfway, through editing a field? Back should revert the changes and stop editing. Only when there was no action does back navigate back through the stack. Intuitively this is how I look at the back button. If anything ever goes wrong, back will fix it.
Gestures and Scrolling Directions
Gestures are a great placebo for Natural Mapping. They seem like a good idea at first but never seem to work out. Unlike normal placebos these can often have the effect of being more detrimental for mapping than beneficial. Quickly, which direction should you swipe to delete an item? Do you scroll the item up or move the content down? I don’t believe there is a convention for swipe gestures so making the assumption that your users have one won’t work. I usually avoid most gestures within an app for this reason.
EditText and Form Field Navigation
While I would prefer to never enter text into any application eventually something will have to go in. I don’t think I’ve ever entered a form (digital or otherwise) and said “That was truly enjoyable” but we can at least strive to make it less painful. Handling Input Types training on the Android developer site should be read and enjoyed. You can setup your form so that you advance to the next field using the keyboard and submit it with the IME_ACTION_DONE feature without ever closing the keyboard. Having to click on a field, edit that field, click on another field is a painful way to enter data.
And if you ever have a user enter data in landscape mode, always include the following option in your EditText field.
Without it the Android keyboard might take over the whole screen. Users will have no idea what they are entering. I can’t imagine a more painful experience than that. (Relevant SO)
- Constrain your UI when the user has to perform a series of actions. Like disabling buttons until the text is entered correctly
- Always visually indicate when you are constraining an action to prevent confusion
- Use dialogs sparingly and only cases where it requires the users immediate attention.
- Stick to Android conventions when building your design. When you are unsure test your assumptions on real people.