Originally posted by Nekhelesh Ramananthan on his blog

While working on Ubuntu Clock App and Flashback I used to always run into small issues like the input fields being hidden by the on-screen keyboard (OSK) on the phone. Back in April 2013 (for starters I cannot believe it has been 8 months already!) I did not have an Ubuntu Phone and hence it was rather difficult to identify these issues on time resulting in commits still being pushed to trunk. With time, I have learnt to address them and hence I thought I share some of those tricks along with some new ones so that you don't have to start from scratch like me or some of the core apps developers.

Preventing UI from being overlapped by OSK

If you look at most applications run on the phone, their UI elements are often given sufficient padding to ensure they are aesthetically pleasing and provide breathing space for the elements. As a result, when the OSK appears it results in about 40% of the screen covered and hiding many application UI elements. This could result in the user searching for vital application elements like buttons and having a rather touch time.

Hence while using input fields like TextField, TextArea it is important to ensure that critical UI elements which need to be visible to the user at all times are not hidden by the OSK. An important thing to keep in mind that you don't really face this issue while testing your application on the desktop. So do make it a point to ensure that you test your commit on a phone or an emulator before commiting to trunk.

One way of doing this in QML is by using a Flickable which automatically allows the user to scroll the interface to find the appropriate content. However this is still cumbersome to make the user scroll in the remaining 60% screen height available to get to the content he/she is looking for. A more clever approach is to anchor those critical UI elements like a button, label to the OSK. The Ubuntu SDK offers a rather clean approach to doing this.

In your main QML file, inside the MainView{} element you can set a property true as shown below,

    anchorToKeyboard: true

This allows any content or UI element that you anchor to the bottom of the application to automatically appear above the OSK. Let's look at an example. We are going to make an account creation page together. It is going to consist of a username, password and email input field. Finally there will be a button to perform the account creation action.

Pay close attention to the anchors of the flickable and the createButton!

    Page {
    id: accountPage

    Flickable {
        id: sampleFlickable

        clip: true
        contentHeight: mainColumn.height + units.gu(5)
        anchors {
            top: parent.top
            left: parent.left
            right: parent.right
            bottom: createButton.top
            bottomMargin: units.gu(2)
        }            

        Column {
            id: mainColumn

            spacing: units.gu(2)

            anchors {
                top: parent.top
                left: parent.left
                right: parent.right
                margins: units.gu(2)
            }

            TextField {
                id: username
                width: parent.width
                placeholderText: "username"
            }

            TextField {
                id: password
                width: parent.width
                placeholderText: "password"
            }

            TextField {
                id: email
                width: parent.width
                placeholderText: "email"
            }
        }
    }

    Button {
        id: createButton
        text: "Create Account"
        anchors {
            horizontalCenter: parent.horizontalCenter
            bottom: parent.bottom
            margins: units.gu(2)
        }
        onClicked: // perform log in function
    }
}

When you use this login page without setting the anchorToKeyboard property to true, it will result in the create account button being hidden as shown in the screenshot below.

However by setting the anchorToKeyboard property to true, you will get a better results as shown. Isn't that much better? By using a flickable, a user will be able to scroll the UI to see other text fields, but the create account button is always visible


The example above is just one use case of many. Another example that comes to my mind is having a search page with a search box below which a list view is shown. Ideally you want to anchor the list view to the bottom of the page. So when the OSK appears, the list view gets anchored to the OSK providing a much better view.

Special Keyboards for specific purposes

Another minor detail that I think improves the user experience is showing the right keyboard. Here is a quote that I have read in several websites about good application design,

A good UI is one which guides and self corrects the user to perform the right action rather than one which shows a notification prompt informing the user that he has made a mistake.

Though I am no designer, when I think about it from the user's perspective I agree to it completely. Who likes to see annoying pop-ups (from the windows XP times) like,

So when it comes to receiving input from the user, one step towards guiding the user is by showing the correct on-screen keyboard. Let me illustrate :-)

Let's say you want to get the user's phone number (commonly seen in messaging apps), it is better to show a keyboard allowing only numeric inputs,

    TextField {
    id: username
    width: parent.width
    placeholderText: "phone number"
    inputMethodHints: Qt.ImhDialableCharactersOnly
}

Let's say you want to get the user's email address, it is better to show a keyboard with common characters such as @ and .com.

TextField {
    id: username
    width: parent.width
    placeholderText: "phone number"
    inputMethodHints: Qt.ImhEmailCharactersOnly
}

As you may have noticed from the above code examples, you can control the OSK type shown using the inputMethodHints method. The Ubuntu SDK is quite powerful (by inheriting and improving on upstream QML widgets). If you would like to get more information about the different textfield method hints, I will refer you to the official documentation found here.

Good Luck with your app! Remember one achieves a great user experience by paying attention to such small details.

Update 1: Just out of curiosity, if you are interested in doing some special actions when the OSK appears and disappears you can do that using the connections elements as shown below,

Connections {
    target: Qt.inputMethod
    onVisibleChanged: console.log("OSK visible: " + visible)
}

Whenever the OSK appears, it will fire the onVisibleChanged signal.

Update 2: One other inputMethodHints that I failed to mention is Qt.ImhNoAutoUppercase. By default the OSK capitalises the first letter of a sentence. This is sometimes deterrent to input fields like username. By setting this method hint, you can disable that feature.

Update 3: I just learned from Jamie Strandboge that the OSK can be hidden using Qt.inputMethod.hide().