We may earn a commission for purchases using our links. Learn more.

After a two month break, Weekend Coder is back with another installment. Today I bring you some Passport specific goodies using the touch enabled keyboard. Ironically enough, I was writing this tutorial about two months ago and this ultimately lead to the development of Work Wide. Perhaps even more ironically, Work Wide shares no code from this tutorial but based off the screenshots you'll probably see the inspiration. However without further ado, let's take a look at some code for keyboard scrolling and gestures.

First the most basic feature to apply keyboard scrolling is to do nothing at all! What I mean by that is Cascades has some magic, if it "sees" there is only a ListView or ScrollView it will automatically keep it in focus and allow for keyboard scrolling. However, sometimes you have other things on the screen that "confuses" Cascades. And from yours (as a developer) and an end user's perspective the only important element on your screen is a ListView (such as a newsfeed), you can set the scroll role to main:

ListView {
                scrollRole: ScrollRole.Main
//...
   }

But then this got me thinking, what if you had two items that you want to allow keyboard scrolling? Say you had something that looked like this (see the resemblance to Work Wide, haha?):

In this case you wouldn't want to use scrollRoll.Main because whichever list is set to main will always take ownership of the keyboard scrolling. Instead you need a mechanism to have the app be aware of which list the user wants to scroll at any given moment. This can be done via requestFocus.

So let's think of the list on the left as "list1" and the list on the right as "list2". If we want list1 to scroll, list1 needs to be in focus and the same is true for list2. To request Focus we can listen for the onTouch event on the list view and call the request:

            ListView {
                id: list1
//...
                onTouch: {
                    list1.requestFocus();
                }
   }

Doing the same for list2 will make it so if the user touches either list, it will be in focus and then from there they could use keyboard scrolling.

To make for a better user experience, in this case it makes sense to have list1 in focus on initial launch of the app. This can be accomplished by using a QTimer to request focus to list1 very shortly after the app is launched. Take a look at the applicationui.cpp and main.qml in the github repo posted at the bottom of this article see the QTimer with the id "initialTimer" to see how I set this feature up.

Finally, while I was thinking about keyboard scrolling I wondered: Could you use the keyboard to do "other things"? Even though I have set up the onTouch for lists to "switch" focus between the two lists that seems a bit clunky. Let me explain what I mean by clunky, if a user is keyboard scrolling one of the lists their finger is obviously on the keyboard. Then to switch lists they'd need to move their finger to the screen. So perhaps a keyboard shortcut would be better? Sure that's better because the user is already touching the keyboard and a shortcut would be "closer". But what I decided was even better was to use the TouchKeyboardHandler.

Using the TouchKeyboardHandler you can listen for keyboard events like when the user touches the keyboard. These events can be mapped to perform whatever you'd like using the same logic as the screen onTouch gesture. So I thought it would be cool to use this to switch focus of the lists. To not interfere with list scrolling, I created a custom (but familiar) gesture of "double tapping" the keyboard to switch focus. The double tap gesture on the keyboard requires a few things: Boolean variable, QTimer, and of course the onTouch listener inside the TouchKeyboardHandler. Putting these together you can have the following code:

Page {
   property bool singleTap: false 

attachedObjects: [
    QTimer {
        id: tapTimer
        interval: 250
        onTimeout: {
            singleTap = false;
            tapTimer.stop();
        }
    }
]
    Container {
        id: main1
        eventHandlers: [
            TouchKeyboardHandler {
                onTouch: {
               if(singleTap == false){
                   singleTap = true;
                   tapTimer.start();
               }
               else if(singleTap == true){
                   if(list1.focused == true){
                       list2.requestFocus();
                   } else{
                       list1.requestFocus();
                   }
               }
                }
            }
        ]
//... rest of main1 Container code…
    }
//... rest of page code…
}

What the code above does is setup a variable called singleTap that is initially set to false. Then if the user taps the keyboard while singleTap is false, it sets singleTap to true and starts a 250 millisecond QTimer. After 250 milliseconds the timer will change singleTap back to false. But if the user taps the keyboard while singleTap is true, pretty much in a normal "double tap" fashion, the onTouch will switch the focus of the lists.

One last thing you'll see in the github code below is leftHighlight and rightHighlight Containers to give a little visual representation to the user as to which list is currently in focus. This requires a few lines of code sprinkled throughout to switch which one is visible depending on focus.

So there you have it, some basic and complex gesture handling of the Passport's touch enabled keyboard. Feel free to poke around the code on github. And for the non-coders I've also added the bar file if you'd like to load this to your Passport to see keyboard scrolling and double tap in action. And as always, I'll be in the comments section to answer any questions.

Read more