Weekend Coder: Handling orientation changes

By Brian Scheirer on 10 Nov 2013 07:34 am EST
2
loading...
0
loading...
41
loading...

While designing my first app that is intended for media consumption (rather than my usual puzzle games), I quickly realized that it is necessary to to take into account orientation changes. The orientation is the direction the device is being held, either landscape or portrait. The idea of properly handling orientation is to effectively use screen real estate for both use cases.

Luckily, like many other things in Cascades, dealing with orientation changes is very easy. Prior to changing any code, if you go to the “Application” tab of the bar-descriptor.xml you will see an orientation dropdown. If it is set to auto-orient, Cascades will know when the orientation changes and attempt to reposition your objects to display properly. Usually this is not ideal, but it's worth taking a look to see how your app looks with Cascades adjusting auto-magically.
Assuming the auto adjust from Cascades is not what you’d like for your app, you can also easily adjust and move around components manually. Let’s take a look at two scenarios/methods for handling orientation changes.

Adjusting Component Properties

This first method will take advantage of adjusting component properties. Take a look at the two screenshots below.


The portrait view has 6 components (only 3 visible), stack one on top of each other in a ScrollView that scrolls vertically. The landscape view has the same 6 components, however they are now stacked left to right and the ScrollView scrolls horizontally.


To control these properties we need to attach the OrientationHandler to our Page. Then within that, the signal onOrientationAboutToChange is fired when the user changes the orientation of the device. So we could have code that looks like:

import bb.cascades 1.0

Page {
    attachedObjects: [
        OrientationHandler {
            onOrientationAboutToChange: {
                if (orientation == UIOrientation.Landscape) {
                    scrollContainer.layout.orientation = LayoutOrientation.LeftToRight;
                    scrollMain.scrollViewProperties.scrollMode = ScrollMode.Horizontal;
                } else {
                    scrollContainer.layout.orientation = LayoutOrientation.TopToBottom;
                    scrollMain.scrollViewProperties.scrollMode = ScrollMode.Vertical;
                }
            }
        }
    ]
  //...
  }

Using Custom Components

Much like I used a custom component in my Asset Selector example, custom components can be used in the Orientation handler. Take a look at these two screenshots for portrait and landscape.


They each contain the same 9 components, however they are arranged so differently that it would be a pain to account for adjusting all the properties. Therefore it is best to define separate user interfaces for each. So I created PortView.qml and LandView.qml files that contained the UI for each view. Then I used a ControlDelgate in conjunction with the onOrientationAboutToChange signal to dynamically load each UI depending on the orientation. The code would look something like this:

import bb.cascades 1.0

Page {
    attachedObjects: [
        OrientationHandler {
            onOrientationAboutToChange: {
                if (orientation == UIOrientation.Landscape) {
                    myDelegate.source = "LandView.qml"
                } else {
                    myDelegate.source = "PortView.qml"
                }
            }
        }
    ]
    Container {
        //Todo: fill me with QML
        Label{
            text: "AWESOME TITLE!"
            textStyle.fontSize: FontSize.XLarge
            textStyle.fontWeight: FontWeight.W100
        }
        ControlDelegate {
            id: myDelegate
            source: "PortView.qml"
            horizontalAlignment: HorizontalAlignment.Center
        }
    }
}

That about does it for handling orientation changes. One more thing to note, Q series (720x720) devices will ignore this code always displaying the portrait UI. Check out the full source code for these two samples from the link below and sound off in the comments with any thoughts!

23 comments

Insync

Thanks!

Posted via CB10

Reyman

Hey, if I got this right, you don't need to make sure the app state remains the same? On Android you need manage all background processes and data when orientation changes because the activity gets destroyed and re-created. That's not the case here?

Posted via CB10

LeroyP09

No cascades does a lot of it and not needed.

Zed 10 - 10.2.0.1047. In your face VZW

Reyman

So what do I have to do when I do a lazy loading of list data and the orientation gets changed? how do I associate the data with the new view?

Posted via CB10

LoganSix

If you set the datamodel to the list, it is still there, so you just need to change the orientation of the list in the onOrientationAboutToChange.

Reyman

Awesome... thanks.

Posted via CB10

Reyman

Sry for commenting again.
This is something one should definitely highlight when it comes to developing for BB10. Really. Android developers will know.

Posted via CB10

ekkescorner

you have to manage the state of your Pages if you swap between qml pages depending on orientation.
Bound List data is there without to do anything, but if you have set properties to store some state, want to scroll to same row as before, ... then you have to set this in the swapped page.
So it's much easier then using Android and all is under your control, but think about persisting your state if changing complete QML pages on orientation change.

nerdydaddyo

When can we see the bar file for this?

I used my Z10 to create this CrackBerry madness!

Brian Scheirer

The source code for the orientation examples are on my github: https://github.com/bcs925/CrackBerry/tree/master/FlipView main.qml has the first example and main2.qml (as well as the two additional qml files) are the second example.
 

STV0726

I hope devs read this because I'm sick of apps that don't support rotation!!!

-STV on Z10STL100-3/10.1.0.4780 TMO US

tommo7788

I hope blackberry are reading this and get the home screen in landscape

Posted via CB10

philchang

Amen! I can't understand why we can't have landscape mode on the home screen.

LoganSix

Now if only the simulator controller would actually rotate the simulator. Ugh.

Brian Scheirer

I haven't used the simulator in ages but does the diagonal bezel swipe from the lower right corner not switch orientation anymore?

Ebscer

Bezel Swipe (or even just clicking) in the lower right corner still works. However, it only works if you are in an app that supports multiple orientations...

LoganSix

That's probably what I need to fix. My initial setting for the app is one orientation.

FuzzyPixel

Depending on your app you may also want to invert the logic and do this in a more "QML-friendly" way: declare a property which is updated when orientation is about to change and use bindings in places where it's needed, something like this:
Page {
id: page

property var orientation: OrientationSupport.displayOrientation

ScrollView {
layout: StackLayout {
orientation:
orientation == UIOrientation.Landscape ? LayoutOrientation.LeftToRight : LayoutOrientation.TopToBottom
}
}

attachedObjects: [
OrientationHandler {
onOrientationAboutToChange: {
page.orientation = orientation
}
}
]
//...
}

FuzzyPixel

Or if you want to be fancy:

Page {
id: page

property string orientation;

Container {
layout: StackLayout {
orientation:
orientation == "landscape" ? LayoutOrientation.LeftToRight ? LayoutOrientation.TopToBottom
}
ImageView {
// automatically picks proper image
imageSource: "asset://image_" + page.orientation + ".png"
}
}

attachedObjects: [
OrientationHandler {
onOrientationAboutToChange: {
updateOrientation(orientation)
}
}
]

function updateOrientation(newOrientation) {
orientation = newOrientation == UIOrientation.Landscape ? "landscape" ? "portrait"
}

onCreationCompleted: {
updateOrientation(OrientationSupport.orientation)
}
}

Brian Scheirer

Seems like a lot more code that does essentially the same thing I have.

Posted via CB10

FortyTwoApps

It's more friendly if you were to change the id of your control, or remove the control all together. Say in a future update you no longer need one of the scroll views, in your code you would need to update the orientation handler, instead of simply removing the control.

abhizone

Thanks for sharing this. I will soon start developing applications for Blackberry :) Need to brush up little tutes for that.