blackberry cascades labs ui xtreme_labs_tech

QML Timer Workaround in BB10

BlackBerry’s Cascades framework allows developers to add a lot of functionality in QML that would otherwise have to be created in C++. The platform is missing one important component however: a timer! Timers are especially useful when you need to create a workaround in your QML to make life easier. Need to defer a view calculation for just a moment later? Want to wait for layout changes in your app to finish, but aren’t exposed to the necessary signals? Right now, there’re only two options:

  • Import the QTimer class. Unfortunately, this will break Momentics’ QML previewer.
  • Call a C++ function, which waits for a QTimer, and then triggers a QML callback that you created. What a pain!

I’ve constructed a simple workaround made entirely from QML that won’t break the Momentics previewer, but is still easy to maintain and extend.

The trick is simple:

  1. Piggy back off of the built-in animations framework to provide the needed timing functionality. Use an animation to change the opacity of a control that is not visible to the user.
  2. Allow the timer owner to set the duration and start the animation countdown without needing to know anything about how time is kept.
  3. Expose a signal that will be emitted when the animation is finished.

I’ve created a sample app on GitHub demonstrating the whole thing working together. The meat of the code is also included below. I hope this will help you keep more of your UI code in QML where it belongs.

// QmlTimer.qml
import bb.cascades 1.0

Container { id: root
    opacity: 0.0

    property int duration: 0
    property bool timerActive: false

    signal triggered

    function startTimer() {
        if (duration == 0) {
            console.log("timer can't start when duration is 0");
            return;
        }

        if (timerActive == true) {
            console.log("timer is already active, not starting");
            return;
        }

        opacity = 0;
        timerActive = true;
        timerAnimation.play();
    }

    function stopTimer() {
        timerActive = false;
        timerAnimation.stop();
    }

    animations: [
        FadeTransition { id: timerAnimation
            fromOpacity: 0
            toOpacity: 1
            duration: root.duration
        }
    ]

    onOpacityChanged: {
        if (timerActive == true && opacity == 1) {
            timerActive = false;
            root.triggered();
        }
    }
}