Tutorial: Customizing text input

Tutorial: Customizing text input

One commonly requested feature is a “widget-based” text input field and today’s tutorial gives you a foundation to build your own. This isn’t a complete implementation, and it only overcomes a few issues related with native.newTextField(), but it should provide a good starting point.

Let’s begin with some basic setup code:

Naturally, a widget like this could end up with an enormous number of options, but let’s start by considering some basic options:

  • top — distance from the top of the screen
  • left — distance from the left of the screen
  • x — location of the widget horizontally (center)
  • y — location of the widget vertically (center)
  • width — width of the field
  • height — height of the field
  • font — Font to use
  • fontSize — size of the font
  • backgroundColor — the color behind the text
  • strokeColor — the color of the stroke around the field
  • strokeWidth — the size of the stroke
  • cornerRadius — if you want rounded corners
  • text — the initial text
  • inputType — the type of keyboard to show
  • listener — the input handler

Obviously this could be extended to include things like the value of the “return” button, having placeholder text that disappears when you first start editing the field, and even skinning features. However, since this function is going to use a native text field, we’ll need to write — at the core — a function to handle editing of the field:

If we want this to be part of the widget library, we simply add it to a module and include the widget library:

This will cause a new function, newTextField(), to be added to the instance of the widget library that has been included in your project. Then, in any scene or module where you require the widget library, the function will be available.

Now let’s define the default option values:

The code above may seem a bit confusing, but we’re simply accepting a parameter to the function called options. The first line creates a table named customOptions which makes sure it’s a Lua table. If you don’t pass the options parameter, an empty table is created. After that, we just set each of the individual options to either the passed value or a default value. For this widget, things like the corner radius and the font size should default to values that adapt to the size of the field.

Creating the visual elements

In this section, we’ll create the visual part of our text field widget, including the native UI element to pair it with:

Here are a few points to consider as you inspect this code:

  • If you round the corners, don’t let the actual text field extend into the corners.
  • Remember to hide the native text field background so that your custom visuals show up.
  • native.newTextField() needs the font string name converted to a native.newFont(). However, the size is a bit tricky because native text fields do not automatically scale. Thus, we must calculate the device’s real scale factor and then multiply the desired font size by that scale factor.

Removing the elements

We need to make sure that when the widget gets removed, the native text field gets removed as well. Previously, we would need to override the removeSelf() function with our own function that would eventually call the original removeSelf(). However, the new finalize event makes this process easier. This allows us to set up a function that’s executed just before the display object is removed from the stage, in case there are related cleanup tasks we need to handle — in this case, removing the native text field just before our custom text field group is removed.

Using the custom text field

Using our new “widget” text field is simple. To place it on screen, our code may look like this:

Retrieve the value of the text field

Set the value of the text field

In summary

This tutorial should get you started with implementing “styled” text input fields and, hopefully, extending them to more complex use cases.


Rob Miracle
[email protected]

Rob is the Developer Relations Manager for Corona Labs. Besides being passionate about helping other developers make great games using Corona, he is also enjoys making games in his spare time. Rob has been coding games since 1979 from personal computers to mainframes. He has over 16 years professional experience in the gaming industry.

19 Comments
  • Dean Hodge
    Posted at 15:34h, 03 December

    Rob, great tutorial but…

    I got super excited for a moment thinking this would resolve the biggest issue with textFields, ie the font size scaling on various devices, especially Android.

    Every time I do a business app, this one issue always bites me, as with many others.

    Hopefully we can get the font size scaling issue resolved soon as it’s been plaguing me and many other developers for a very long time.

    Please try and find a solution for this issue.

    • Chris
      Posted at 16:01h, 03 December

      +1 on the font scaling on devices

    • Rob Miracle
      Posted at 16:03h, 03 December

      Did you try this? I ran the code on my iPhone 5, iPad 4 and Google Nexus 7 (with a 320×480 base content area) and the font size was consistent from device to device. There is code in there to maintain the scaling.

      Rob

      • Kerem
        Posted at 11:54h, 05 December

        Just tried the code on my Android 2.2 Samsung Galaxy S. The font size issue is still there. Not sure if this is due to the real old OS revision.

        • Rob Miracle
          Posted at 17:32h, 05 December

          Can you reply to this on the forum post and provide a screen shot?

  • Star Crunch
    Posted at 15:03h, 04 December

    I seem to remember having to explicitly removeSelf() widgets… have those been rewritten with finalize in mind? That is, can I get rid of that handling code?

    • Rob Miracle
      Posted at 15:20h, 04 December

      All display objects need to be explicitly removed and nil’ed with the exception of Storyboard where display objects in the scene’s view are removed for you when the scene is destroyed.

      Rob

      • Star Crunch
        Posted at 16:57h, 04 December

        Sorry, I wasn’t precise enough; that probably sounded like a bit of a trivial question. I meant is removeSelf() still necessary for widgets versus, say, group:remove()’ing or removing the parent group, on account of the logic being moved into the finalizer. At least, I’d assumed those don’t invoke the (possibly overridden) removeSelf() method…

        Of course, maybe I’ll test and see my assumptions were wrong all along. 🙂

  • Kerem
    Posted at 00:14h, 05 December

    Thanks for a great tutorial. This is a great starting point for what I hope will evolve into a formal Corona Labs widget.newTextField() soon.

    Question – how can we extend the functionality so that if a new parameter (ie eraseInitialText) is set to true then the initially supplied text is erased when user first taps into this input field? I am able to do this in the began field of my listener function but I would like to push this code into the widget extension code so it can be reused. Is this possible? Thanks

  • Sean
    Posted at 06:54h, 05 December

    Hey Rob, will these text fields scroll in a widget ScrollView now? That has always been a big issue for me; getting the text fields to scroll with the rest of the screen. Is there any sort of time frame on when this will be implemented in the actual widget code base?

    • Rob Miracle
      Posted at 16:31h, 06 December

      I didn’t try it, but it should. The sync code keeps the native text field wherever the object is. Depending on how fast you scroll the scrollView there may be some lag while the system moves the native.newTextField.

      Rob

  • Kawika
    Posted at 10:03h, 08 December

    Anyone using “Text Candy” by X-PRESSIVE.COM?

  • Kawika
    Posted at 12:35h, 08 December

    Anyone using “Widget Candy” by X-PRESSIVE.COM?

  • bobcgausa
    Posted at 06:49h, 15 January

    i use corona to teach students who use the simulator on mac or windows and who do not necessarily have a droid.

    “Since this module still utilizes native text fields, it will draw the widget background on the Windows Corona Simulator, but the text field will not function.”

    Really, how hard can it be to have a single line text box that is multi-platform?
    This is a huge restriction for classroom use.

    • Rob Miracle
      Posted at 17:51h, 15 January

      We’ve explained this on many occasions. Corona SDK is based on OpenGL. On OS-X, iOS and Android, the OS’s permit native objects and the OpenGL canvas to occupy the same window. On Windows, they do not permit native objects and OpenGL objects to co-exist in the same window. Mircosoft lets this happen for DirectX based apps, but we are an OpenGL based app.

  • sangu
    Posted at 01:07h, 17 September

    widget.newTextField({}) is showing error in my code, while referencing to widget.
    does it support in pro-corona or i m doing something wrong in code?
    local widget = require(“widget”)
    local myTextField = widget.newTextField(
    {
    top = 10,
    left = 20,
    width = 200,
    height = 30,
    cornerRadius = 8,
    strokeWidth = 3,
    backgroundColor = { 1, 1, 1 },
    strokeColor = { 0, 0, 0 },
    font = “Helvetica”,
    fontSize = 24
    –listener = textFieldHandler
    }

    • Rob Miracle
      Posted at 17:28h, 17 September

      Please ask this this in the forums.

      Thanks
      Rob

  • Julius Bangert
    Posted at 06:21h, 08 September

    Is there any module or plugin anyone has come up which that offers typeahead / autocomplete functionality?
    So as the user types the first few letters, something in the UI near the text input suggests terms pulled from a lua table?
    This would be so good.