Simple Active Frames

One of the features that make Native Cascades stand out from Android ports, as well as from competitors like iOS is Active Frames.  Active Frames are a useful tool that can provide important app information to users in the active frames pane on BlakcBerry 10.  Information such as recently viewed articles in an RSS feed app, or latest tweets can provide useful information for users without having to enter the application.  Developers have the ability to pick and choose what they want to show users in active frames and aren't restricted to one definition or use-case.  I personally like to add a nice cover image to the active frame even if I'm not going to invest the time into coding some important information for my active frames.  It looks more professional and visually appealing to users to give them that all-around BlackBerry 10 experience.

Before we get started here are the files we will be making use of:

  • ActiveFrameQML.cpp (user created)
  • ActiveFrame.hpp (user created)
  • ApplicationUI.cpp
  • AppCover.qml (user created)
  • main.qml

Screenshot

 

 

 

ActiveFrameQML.cpp

Here is where we setup the Active Frame object as well as the functions to set the image and text on cover.  As you can see we're creating an object that will pull the UI information from the AppCover.QML we will create.  You'll see later in this tutorial that we link to the object names of the m_coverLabel and m_coverImage so that we can interact with these aspects in QML.  For now All you need to do is create a .cpp named "ActiveFrameQML.cpp" and directly copy and paste the code below into it.

 
#include "ActiveFrameQML.h"

#include <bb/cascades/SceneCover>
#include <bb/cascades/Container>
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>

using namespace bb::cascades;

ActiveFrameQML::ActiveFrameQML(QObject *parent)
    : SceneCover(parent)
{
    QmlDocument *qml = QmlDocument::create("asset:///AppCover.qml")
            .parent(parent);
    Container *mainContainer = qml->createRootObject();
    setContent(mainContainer);

    m_coverLabel = mainContainer->findChild<Label*>("TheLabel");
    m_coverLabel->setParent(mainContainer);

    m_coverImage = mainContainer->findChild<ImageView*>("TheImage");
    m_coverImage->setParent(mainContainer);
}

void ActiveFrameQML::update(QString appText) {

    m_coverLabel->setText(appText);
}
void ActiveFrameQML::updateImage(QUrl appText) {

    m_coverImage->setImageSource(appText);
}

ActiveFrameQML.hpp

Here we simply create the header file for the .cpp file we just created.  The header identifies the functions and objects in the .cpp file.  You can just straight copy and paste this code into a header file that you create called "ActiveFrameQML.hpp".  

 
#ifndef ACTIVEFRAMEQML_H_
#define ACTIVEFRAMEQML_H_

#include 
#include <bb/cascades/Label>
#include <bb/cascades/ImageView>
#include <bb/cascades/SceneCover>

using namespace ::bb::cascades;

class ActiveFrameQML: public SceneCover {
    Q_OBJECT

public:
    ActiveFrameQML(QObject *parent=0);

public slots:
    Q_INVOKABLE void update(QString appText);
    Q_INVOKABLE void updateImage(QUrl appText);

private:
    bb::cascades::Label *m_coverLabel;
    bb::cascades::ImageView *m_coverImage;
};

#endif

ApplicationUI.cpp

We have to put in some tiny code into the ApplicationUI.cpp so that we access our Active Frame functions directly in QML by typing "activeFrame" whenever we want to access a function.  To do this you will add the following code in the main Object portion of your ApplicationUI.cpp.

 
ActiveFrameQML *activeFrame = new ActiveFrameQML();
        bb::cascades::Application::instance()->setCover(activeFrame);
        qml->setContextProperty("activeFrame", activeFrame);

make sure the above code is placed directly before this code...

 
AbstractPane *root = qml->createRootObject();

AppCover.qml

Now we get to do some of the more interesting stuff like design the layout of how our Active Frame is going to look as well as what images or text will be shown.  As you can tell it doesn't look like anything too complicated.  The important thing to note is that the ImageView and the Label have objectnames which will link them to the cpp functions we created earlier.  The rest of the code on this page is simply to design how an image and text will be shown in the Active Frame.  I've created a black rectangle at the bottom of the active frame that has an opacity of 0.9 so that some of the image from the ImageView can be seen while also providing a dark background for the label we will show.  You can create a qml file called "AppCover.qml" and straight copy and paste the code below into it.  

 
import bb.cascades 1.0

Container { 
    layout: DockLayout {
        
    }   
    Container {        
        layout: DockLayout {}
        background: Color.Black
        horizontalAlignment: HorizontalAlignment.Fill
        verticalAlignment: VerticalAlignment.Fill
        
        ImageView {
            objectName: "TheImage"
            imageSource: "asset:///images/ActiveFrame.png"
            scalingMethod: ScalingMethod.AspectFill
            horizontalAlignment: HorizontalAlignment.Fill
            verticalAlignment: VerticalAlignment.Fill
        }
        
        Container {
        	layout: DockLayout {
             
         }	
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Bottom
            
            Container {
                preferredWidth: 320
                preferredHeight: 100
                leftPadding: 10
                rightPadding: 10
                bottomPadding: 10
                opacity: 0.9
                background: {
                    if(label.text == "")
                        Color.Transparent
                    else 
                        Color.create("#121212")
                        
                }
                layout: DockLayout {}
                Label {
                    leftPadding: 10
                    rightPadding: 10
                    bottomPadding: 10
                    id: label
                    objectName: "TheLabel"
                    horizontalAlignment: HorizontalAlignment.Left
                    verticalAlignment: VerticalAlignment.Center
                    multiline: true
                    text: ""
                    textStyle.color: Color.White
                    textStyle.fontSize: FontSize.PointValue
                    textStyle.fontSizeValue: 8
                }
            }
        }
    }
}

Below are an example of how the active frame will look without anything getting set (i.e. it just takes the default information from this QML. Notice in the code above how I set the dark rectangle to be invisible if there is no text set and notice that the imageview just takes a default image from the assets.  Remember, this is just a tutorial so you can, and I certainly recommend, playing around with the layout to make your app standout and represent what you want it to do!

Main.qml

The last part of this tutorial focuses on passing user inputed data to be shown in the active frame.  Below I've created a page with a dropdown menu that changes the image in the imageview depending on what the users chooses.  Below that I have a Label who's text gets changed by what the user inputs into the textfield below it.  Below all of this I have a buttong that sets the active frame.  I have it set so that onClicked it uses the imageview image and the label text and sets them as the image and label portion of my active frame.  Because we made the activeFrame functions available to us in the qml we can simply use the activeFrame.update() and activeFrame.updateImage() in the onClicked to set the label and text.  Both of those functions were created in the ActiveFrameQML.cpp.  If you want to add another label or object to your active frame you would create another function to set, maybe a date label for instance.  Notice the bottom part of the code where you find the function onThumbnailed and the connect function below it inside onCreationCompleted, this connects the created function of onThumbnailed with the thumbnail action of send an app to Active Frame.  It will let you know when the app as become thumbnailed in the active frame.  It's not terribly necessary but it is useful for debugging.  I will do another tutorial explaining some more things you can do with the thumbnail stuff.

 
import bb.cascades 1.0

Page {
    Container {
        leftPadding: 20
        rightPadding: 20
        horizontalAlignment: HorizontalAlignment.Center
        layout: StackLayout {
            orientation: LayoutOrientation.TopToBottom
        }
        DropDown {
            topPadding: 20
            horizontalAlignment: HorizontalAlignment.Center
            id: dropdown
            title: "Your favourite BlackBerry is:"
            options: [
                Option {
                    text: "Q10"
                    value: "asset:///images/image1.jpg"
                    selected: true
                },
                Option {
                    text: "Z10"
                    value: "asset:///images/image2.jpg"
                },
                Option {
                    text: "Z30"
                    value: "asset:///images/image3.jpg"
                }
            ]
            onSelectedOptionChanged: {
                image.imageSource = selectedOption.value
            }
        }
            ImageView {
                topPadding: 20
                horizontalAlignment: HorizontalAlignment.Center
                preferredHeight: 400
                preferredWidth: 400
               id: image
               imageSource: "asset:///images/image1.jpg"
               scalingMethod: ScalingMethod.AspectFill
            }
        Label {
            topPadding: 20
            horizontalAlignment: HorizontalAlignment.Center
            id:label
            // Localized text with the dynamic translation and locale updates support
            text: qsTr("Hello World") + Retranslate.onLocaleOrLanguageChanged
            textStyle.base: SystemDefaults.TextStyles.BigText
        }
        TextField {
            topPadding: 20
            horizontalAlignment: HorizontalAlignment.Center
            id: textField
            hintText: "I love my BlackBerry because..."
            onTextChanging: {
                label.text = textField.text
            }
        }
        Button {
            topPadding: 20
            horizontalAlignment: HorizontalAlignment.Center
            id: button
            text: "Set Active Frame"
            onClicked: {
                activeFrame.update(label.text);
                activeFrame.updateImage(image.imageSource);
            }
        }
    }
    function onThumbnailed(){
        console.log("Active Frame Location Toggled")
    }
    onCreationCompleted: {
        Application.thumbnail.connect(onThumbnailed);
    }
}

The important thing to keep in mind with Active Frames is that they aren't meant to be your entire application on a smaller area, they are supposed to show the few important details that will improve user multitasking.

As always if you have any questions don't be afraid to give me a shout on Twitter @ElBranduco.  Now go be an active frame master :P.

Brandon Orr

Transportation Planner (University of Waterloo Graduate) & Blackberry 10 Developer (PinGuin App) part of the open source BB team.

Website: appworld.blackberry.com/webstore/vendor/65375/

Leave your comments

Post comment as a guest

0

People in this conversation

Subscribe to the official OSBB BBM Channel!

osbbchannelQR

C00013E89

Back to top