While doing mobile development, one of the most frustrating things has been form input.
If you’ve looked at any Playbook development, you’ll see QNX has something called ReturnKeyType specifically for this reason.
Being as stubborn as I am, I wanted a plain Flex approach at accomplishing what I wanted, and not to use the QNX library.

The Problem

When a series of form inputs are displayed on a mobile device, consideration for the on screen keyboard must be taken. In most scenarios, the operating system will shift your application up for you, but getting to the next field below it can be troublesome.

Take a look at this example in my current mobile app, Crash:

Inputs Covered Inputs Uncovered
Inputs Covered Inputs Uncovered

As you can see, when the user has the keyboard in position, the next TextInput is barely in view, and extremely difficult to tap. What’s more, is if you ARE able to tap it, it seemingly lines it up perfect so you can’t tap the one just below it.

I set out to find a solution that was easy to understand, and really easy to implement.

The Solution

It turns out, in Flex 4.5, the TextInput class now dispatches FlexEvent.ENTER when the enter key is pressed. From the ASDocs directly, the statement appears:

This control dispatches a FlexEvent.ENTER event when the user pressed the Enter key rather than inserting a line break, because this control does not support entering multiple lines of text.

AHA! It’s obvious now! I just listen for this event… and… then… do… something?

Yep! That’s exactly right! I’ll skip the banter and get right to the code:

[sourcecode language=”actionscript3″]
override protected function partAdded(partName:String, instance:Object):void
{
switch (instance) {
case this.txtInpName:
case this.txtInpPhone:
case this.txtInpAddress1:
case this.txtInpAddress2:
case this.txtInpLicense:
TextInput(instance).addEventListener(FlexEvent.ENTER, this._onPressEnter, false, 0, true);
break;
}
}
[/sourcecode]

Simply put, whenever a part from the skin is added, and I can identify it as one of my TextInputs, I simply listen for the FlexEvent.ENTER event, and handle it as such:

[sourcecode language=”actionscript3″]
private function _onPressEnter(event:FlexEvent):void
{
var nextFocusObj:IFocusManagerComponent = null;

var focusMap:Dictionary = new Dictionary(true);

focusMap[this.txtInpName] = this.txtInpPhone;
focusMap[this.txtInpPhone] = this.txtInpAddress1;
focusMap[this.txtInpAddress1] = this.txtInpAddress2;
focusMap[this.txtInpAddress2] = this.txtInpLicense;
focusMap[this.txtInpLicense] = null;

nextFocusObj = focusMap[event.target];

if (null !== nextFocusObj) {
this.focusManager.setFocus(nextFocusObj);
} else {
FlexGlobals.topLevelApplication.setFocus();
}
}
[/sourcecode]

Here I’ve simply created a mapping from one input to the next. this.txtInpName will map to this.txtInpPhone as it’s the next in order, this.txtInpPhone to this.txtInpAddress1 and so on.
The special case is the last TextInput item, and I’m assigning null to the mapping. Furthermore, when the nextFocusObj is null, it merely calls setFocus() on the Application itself.

This isn’t the CLEANEST approach in my mind, because there is some setup you have to do first, but it does work.

For those that are going to say, “Why not just use FocusManager::getNextFocusManagerComponent() method to get the next item.” Well, honestly, it wasn’t working as I expected. It was selecting some arbitrary button on the screen; certainly not what I had hoped/expected to see. Thus, I have to be a bit more explicit.

I’ve tested this on the Playbook, and it works great! When the last text input is reached and the user hits Enter/Return, the Application gets focus and the keyboard automatically hides.
Win!