Native Text Input with StageText

One of the major new features of AIR 3 (release candidate available on Adobe Labs) is the introduction of the StageText API. StageText allows developers to place native text inputs in their mobile AIR applications rather than using the standard flash.text.TextField API. StageText is essentially a wrapper around native text fields, so the resulting input is identical to the text input fields used in native applications. (Note that StageText is only for the AIR mobile profile; the StageText APIs are simulated on the desktop, but they do not result in native text inputs on Mac or Windows.)

Advantages of Using StageText

There are several advantages to using StageText over flash.text.TextField in mobile applications:

  • Both iOS and Android have sophisticated auto-correct functionality that StageText allows AIR applications to take advantage of.
  • The autoCapitalize property of StageText allows you to configure how auto-capitalization is applied to your text field. Options are specified as properties of the AutoCapitalize class and include ALL, NONE, SENTENCE, and WORD.
  • StageText allows you to control the type of virtual keyboard that is displayed when the text field gets focus. For example, if your text field is requesting a phone number, you can specify that you want a numeric keypad, or if you’re asking for an email address, you can request a soft keyboard with an "@" symbol. Options are specified as properties of the SoftKeyboardType class, and include CONTACT, DEFAULT, EMAIL, NUMBER, PUNCTUATION, and URL.
  • In addition to controlling the type of virtual keyboard, you can also configure the label used for the return key. Options are specified as properties of the ReturnKeyLabel class, and include DEFAULT, DONE, GO, NEXT, and SEARCH.

The Challenges of Using StageText

On mobile devices, StageText provides much more powerful text input capabilities than flash.text.TextField, however there are some challenges to adding native visual elements to AIR applications.

StageText is Not on the Display List

StageText is not the first time we’ve exposed native functionality directly in AIR. The StageVideo class (mobile and Adobe AIR for TV) allows video to be rendered in hardware at the OS level, and StageWebView (mobile only) allows HTML to be rendered with the device’s native HTML engine. All three of these features have similar benefits (native performance and functionality), but they also share the same unusual characteristic: although they are visual elements, they are not part of the Flash display list. In other words, like StageVideo and StageWebView, StageText does not inherit from DisplayObject, and therefore cannot be added to the display list by calling the addChild() function. Instead, StageText is positioned using its viewPort property which accepts a Rectangle object specifying the absolute (that is, relative to the stage) coordinates, and the size of the native text field to draw. The text field is then rendered on top of all other Flash content; even if Flash content is added to the display list after a StageText instance, the StageText instance will always appear to have the highest z-order, and will therefore always be rendered on top.

In order to help address this behavior, StageText has has a function called drawViewPortToBitmapData. The drawViewPortToBitmapData function provides similar functionality to the IBitmapDrawable interface when used in conjunction with the BitmapData.draw function. Specifically, you can pass a BitmapData instance into the drawViewPortToBitmapData function to create a bitmap identical to the StageText instance. You can then toggle the visible property of your StageText instance, add the bitmap copy to the display list at the same coordinates as the viewPort of your StageText, and then you can place other Flash content directly on top without your StageText instance showing through. It seems like a lot of work, but it’s actually very easy to implement (especially when nicely encapsulated), and provides a good work-around for the fact that native visual elements do not render through the Flash pipeline. (Note that StageWebView also has the drawViewPortToBitmapData function which allows for the same work-around.)

StageText Does Not Have Borders

Something else that sets StageText apart from flash.text.TextField is the fact that it is not rendered with a border. There were two primary reasons for this decision:

  1. Developers will frequently want to customize their StageText borders.
  2. Native text inputs in native applications are sometimes rendered without any borders, especially on iOS. (For an example, compose a new email in the Mail application and note how the "To" and "Subject" fields have dividers between them, but no borders around them.)

Unfortunately, drawing borders around native text fields isn’t as easy as it sounds. In order to perfectly vertically center text between horizontal borders, and to constrain the text perfectly within vertical borders, developers need access to sophisticated font metrics APIs which are available for the two different text engines in Flash (flash.text and flash.text.engine), but they are not available for StageText. Drawing a perfectly sized and positioned border around a StageText instance so that it will work with different fonts and font properties, and work consistently across platforms, is somewhat challenging.

Solutions

Now that I’ve pointed out the challenges of working with StageText, it’s only fair that I provide some solutions.

For Flex Developers

Flex will address the two challenges of working with StageText described above (the fact that it’s not part of the display list, and the drawing of borders) by encapsulating StageText inside of spark.components.TextInput. The TextInput component will worry about drawing a border around the StageText instance, and as long as you use the Flex APIs for manipulating the display list (as opposed to manipulating the display list at the Flash API level), Flex will also manage the viewPort property for you. In other words, Flex will give you get all the advantages of StageText without you having to manage it yourself.

For ActionScript Developers

Developers who are writing in ActionScript directly rather than using Flex have a few options:

  1. Use the StageText APIs directly. This is probably the least practical approach since you will likely find that trying to manage the display list, and trying to manage visual elements not on the display list in a completely different way, will be complex and error-prone.
  2. Encapsulate StageText. You can always do what the Flex team did, and encapsulate StageText to make it easier to work with. This is a fair bit of work, but in the end, it will make it much easier to manage, and will probably prove to be a good time investment.
  3. Use the NativeText class. While validating the encapsulation of StageText, I wrote a pretty comprehensive wrapper which makes working with StageText much easier (details below).

Introducing NativeText

NativeText is a wrapper around StageText which makes adding native text input functionality to your ActionScript application much easier. NativeText has the following advantages:

  • It makes StageText feels like it’s part of the display list. You can create an instance of NativeText, give it x and y coordinates, and add it to the display list just like you would any other display object. All the management of the viewPort is completely encapsulated.
  • It’s easy to add borders. NativeText does the work of drawing borders such that the StageText instance is vertically centered and horizontally bound. You can even change the border’s thickness, color, and corner radius.
  • It’s easy to add content on top because it manages the bitmap swapping for you. NativeText has a function called freeze which does all the work of drawing the StageText to a bitmap (including the border), hiding the StageText instance, and positioning the bitmap exactly where the StageText was. Therefore, if you want to place content on top of a NativeText instance (for instance, an alert box), just call the freeze function first, and everything will work perfectly. When you’re done, call unfreeze, and the bitmap is replaced with the StageText instance and disposed of.
  • Support for multi-line text inputs. NativeText supports text fields of one or more lines. Just pass the number of lines of text you want into the constructor (this is the one property that cannot be changed dynamically), and both the border and viewPort will be properly managed for you.
  • Cross platform. The trickiest part of writing NativeText was making sure it rendered properly on all our reference platforms (Mac, Windows, iOS, and Android) which use different fonts, have different sized cursors, etc. NativeText lets you use any font, font size, and border thickness you want, and your text input should render properly and consistently on all supported platforms.

NativeText is included in a project called StageTextExample. It is open-source, and the code is available on GitHub (or you can download the ZIP file for importing into Flash Builder). This is something I worked on independently, and is not an officially supported Adobe solution, so although I’ve found that it works pretty well, it’s certainly possible that you could discover bugs or use cases it does not take into account. If that’s the case, let me know and/or feel free to hack away at the code yourself.

34 Responses to Native Text Input with StageText

  1. Chris Gannon says:

    Excellent, excellent, excellent! This article (and new AIR 3.0 functionality) addresses a huge wad of issues I’ve been having. I’m extremely grateful for all of Adobe’s hard work!

  2. Hoss Gifford says:

    Great work Christian, much appreciated. You just saved a lot of us a lot of time. 🙂

  3. Joseph says:

    Flex Mobile, especially on iOS has been good in general, but not optimal like Titanium’s performance and native UI skins (for Flex devs use e-skimo).

    With the lack of customization in Titanium, and the liberty so draw on a stage such as Flash, demonstrates that Appcelerator is still a primitive tool.

    Flash Builder has the Design View… (drop & layout your components) and dribble back in Actionscript View.

    Currently, Titanium is better for it’s performance.

    I would love to have Flex export to iOS with a performance matching Titanium by adding native UIs that the iOS currently has.

    Adobe can take it all the other way as oppose to Titanium. By Just adding Native Components, example:

    Would that be possible?

    In this article, I guess after the text input, should probably be the Picker, and all components native to iOS, Android…

    Though I love Flex, it’s platform, libraries, of out of the box features, MXML, and functionalities, Utils out there… it’s community, I would really hope Adobe is including all the UIs of iOS & Android natively while retaining MXML, and Actionscript.

    Maybe a long shot, but that would definitely keep them the kingmaker software-tool company, for all screens and applications.

  4. Pingback: StageText в AIR3 | ActionScript 3 по-русски

  5. Pingback: Flex SDK 4.6和Flash Builder 4.6的新特性 | HowardWu

  6. Pingback: Cool Stuff with the Flash Platform - 9/19/2011 | Remote Synthesis

  7. Thanks very much for posting this. One thing I had to do to get it to work was add the compiler flag:

    -swf-version=13

    Otherwise it wouldn’t find the class at runtime when targeting AIR 3 in the descriptor.

  8. One more problem, freeze() doesn’t seem to be working on a Nexus One running 2.3.6.

    The following line:

    this.st.drawViewPortToBitmapData(bmd);

    Results in an exception:
    “ArgumentError: Error #2004: One of the parameters is invalid.
    at flash.text::StageText/drawViewPortToBitmapData()”

    The bitmapdata object looks fine, has the right width/height etc.

  9. Francisc says:

    Excellent news, thank you.

  10. Pingback: News Flash Weekly: Announcing Flash Player 11 and AIR 3 - Flash Speaks Actionscript

  11. Pingback: Slides, Links, and Questions From my MAX 2011 Presentation « Christian Cantrell

  12. Pingback: arnotify » MAX 2011: Mobile apps that WOW!

  13. Alejandro says:

    I am having problem implementing the inpunt text on some Android devices. I would like to use the StageText and review if it does not have the problem. I tried to run the example but I haven’t found the SDK 4.5.2 with AIR 3 C

    Regards

  14. Babak says:

    Hi

    I’m using TextInput in my mobile project (using Flex 4.6 and Flash builder 4.6)
    in textInput Click event won’t fire. But if I manage to click the border of TextInput then click will work.

    focuseIn won’t work on device either. I tried to use focusIn on IOS (iPad 2) and it doesn’t work however it seems to work on Flash builder’s simulator.

    Any help would be greately appreciated.

  15. Pingback: Zeh Fernando » Blog Archive » Using StageText for AIR applications

  16. Saar Bar Shalev says:

    hey Christian, thanx a lot

    i wonder how would you use NativeText with some thing like InteractiveObject’s softKeyboardInputAreaOfInterest so that the entering native keyboard would not push the upper part of the app out of site but rather superimpose on top of the app

    thanx
    Saar

  17. Saar says:

    hey Christian

    is there a way to control the softkeyboard entrance so that it will appear on top of the app instead of “pushing” it?

    thanx

  18. Dave Cates says:

    Babak – it’s because the text is rendered above all other display list objects – as Christian described above. StageText doesn’t respond to the usual display list events due to this – just like StageWebView.

    You therefore need to use his NativeText 🙂

  19. Gil Amran says:

    Hi,
    I needed a NativeText field and found this one! great job!
    BUT few things:
    * Setting the “visible” will cause infinite loop.
    * Key_Down does not fire! How can I tell when the user finished entering text?

    Thanks

  20. Robert Trimmons says:

    Still in the same boat though with mobile text. How do you render HTML? I have a TextArea in a little chat app that I tricked into displaying HTML text via:

    StyleableTextField(textArea).htmlText += some html text;

    Now StyleableTextField doesn’t exist. How do I get HTML text rendered with Stage Text?

  21. Chris Gannon says:

    Is the textfield supposed to be selected when you use NativeText.freeze(); ?

  22. Pingback: Android TextFieldType.INPUT for digits only! | free icons download

  23. Den says:

    How to draw StageText without cursor and “x” sign?
    freeze() function copy them to bitmap data… not good.

  24. Matt says:

    Why is there no get text?
    e.g trace(_nt.text);

    I had to add the getter

    public function get text():String
    {
    return this.st.text;
    }

  25. Den says:

    Damn, no keyDown event with stagetext on Android, no punctuation mode, no reliable way to keep soft keyboard opened and restrictions are working wrong (still see suggestions from disabled symbols in the soft keyboard). Waiting for StageText updates in AIR 3.4

  26. Andrew Day says:

    If you’ve all had trouble with freeze();

    change line 286 of NativeText.as from

    var bmd:BitmapData = new BitmapData(this.st.viewPort.width, this.st.viewPort.height);

    to

    var bmd:BitmapData = new BitmapData(this.st.viewPort.width, this.st.viewPort.height,true, 0x00000000);

  27. Andy Kirkham says:

    I am working on a mobile application with Flex 4.6 which uses diferent instances of TextInput in different view states. The problem is that when I change currentState, the TextInputs in the new state do not initially display their text and only render after a significant time lag.
    I wonder if there is a way of forcing the stage text in all the TextInputs to refresh instantly

  28. Pingback: kurt grung | AS3 Native Text using AIR 3 StageText

  29. Jörg says:

    Thanks Christian, you saved my day.
    After a few adjustments, this was perfect for our latest AIR iOS project. 🙂

  30. DudeGuy says:

    StageText doesn’t fire for numbers on Android. Nice work, I guess users with email addresses can’t have numbers – par for the course