Weekend Coder: More custom UI's with Fancy Transitions

By Brian Scheirer on 23 Feb 2014 07:08 pm EST
4
loading...
13
loading...
37
loading...

Since BlackBerry 10 Cascades came out a little less than two years ago there have been three major releases of tools and APIs for developers to play around with. And I, like many weekend coders, have spent most of my time trying to use those tools for their somewhat obvious purposes. But as the tool releases have slowed and we have all had time to gain some mastery of the provided tools it’s time to for us developers to create some custom user interfaces and experiences.

We are already starting to see developers expand the native tools with some of their apps such as Blaq, Sochi 2014, and Tilt. A few weeks ago, I shared a sample code base to create a similar UI/UX to the Sochi 2014 app and today I have another sample that I call “Fancy Transitions.”

Before I go any further, I would like to warn everyone that this sample may not be for a novice developer. I have to use quite a bit of math and I am only showing about half of the code in this article. If you follow what I have posted in this blog, the parts I don’t show should make sense as well.

Fancy Transitions shakes up the typical navigation flow where one page slides over top the other page. Rather than a simple slide, I’ve changed it so the page the user is currently on slides to the left and goes back into the screen. At the same time, the new page appears to come up from the back and slides around the right side of old page and becomes the new top. As illustrated below this figure:

This is all accomplished using some well timed animations and a built-in function called swap(). Let’s first take a look at the animations involved. And let’s think of the red Container and blue Container independently. So first the red Container needs to go left, then right, and appear to fall back:

ParallelAnimation {     animations: [         ScaleTransition {             toX: 0.85             toY: 0.85             duration: 400         },         SequentialAnimation {             animations: [                 TranslateTransition {                     toX: -320                     duration: 400                     easingCurve: StockCurve.CubicInOut                 },                 TranslateTransition {                     toX: 0                     duration: 400                     easingCurve: StockCurve.CubicInOut                 }             ]           }     ] }

Then the blue Container needs to go right, then left, and appear to come forward:

ParallelAnimation {     animations: [         ScaleTransition {             toX: 1.0             toY: 1.0             duration: 700         },         SequentialAnimation {             animations: [                 TranslateTransition {                     toX: 400                     duration: 400                     easingCurve: StockCurve.CubicInOut                 },                 TranslateTransition {                     toX: 0                     duration: 400                     easingCurve: StockCurve.CubicInOut                 }             ]         }     ] }

A few more notes about the two code snippets, I have applied an easing curve to each to give a more fluid look to the animation. Also, notice that the duration of each animation line up. The blue scaling is the only one that doesn’t total 800ms to give a better “snap” effect. Feel free to tweak these to your own liking.

Now we need to have these two Containers swap places midway through the animations so the blue is on top of the red. I have accomplished this with a well-timed swap function inside a QTimer:

QTimer {     id: swapTime     interval: 500     onTimeout: {        mainCont.swap(0, 1)        swapTime.stop();      } }

This is a simple function that swaps the positions of two Containers. And since I have these two Containers in a DockLayout the swap changes their position relative to the screen depth.

So if we wanted to control this effect with a button we’d have something like:

 Button {     onClicked: {         swapTime.start();         redGoBackRight.play(); //assume red animation id was redGoBackRight         blueGoForwardRight.play() //assume blue animation id was blueGoForwardRight     } }

Tweaking these animations we can easily get the reverse effect, I have done that in the sample code so I won’t explain it here. But buttons in apps are not what BlackBerry 10 is all about, we use SWIPES! And since there is no built in swipe gesture, let’s go ahead and create one.

First at my main Page level I have defined two variables “startPosition” and “finalPosition”. And then in the main Container level I define an onTouch signal like the following:

onTouch: {             if (event.isDown()) {                 startPosition = event.windowX;                       }             if (event.isUp()) {                 finalPosition = event.windowX;                 var directionSwipe = finalPosition - startPosition;                 var enoughSwipe = Math.abs(directionSwipe)                 console.log(finalPosition + ", " + startPosition)                                  if (enoughSwipe > 150) {                     if (directionSwipe > 0) {                         console.log("back swipe occured")                         swapTime.start();                         redGoBackLeft.play();                         blueGoForwardLeft.play()                                          } else if (directionSwipe < 0) {                         console.log("forward swipe occured")                         swapTime.start();                         redGoBackRight.play();                         blueGoForwardRight.play()                     }                 }         } }

So what I have happening in this code is as soon as the user presses down on the screen the startPosition is recorded. Then as soon as the user lifts up their finger the finalPosition is recorded and some logic happens.

To determine the direction, I take the difference of the two positions. To determine if the user has moved their finger in a swiping like gesture, I take the absolute value of that difference. From there if the absolute value, the variable I named enoughSwipe, is greater than 150 pixels the logic continues. If not then not enough of a swipe occurred to register as a swipe. Now looking at the direction of the swipe, if the difference is greater than 0 the swipe is what we think of as a “back swipe” and if it is less than 0 it is what we would think of as a “forward swipe.”

Along the way I have a few console.log() so I can see what is happening in my console in Momentics. This onTouch needs to be a bit expanded to account for another swipe once the blue screen in on top (need different animations to occur) and if you take a look at the sample I have done that for you as well.

Finally, this brings me to what you see in the video at the top of this post. I have taken the methods explained above and applied them to a real user interface to show it off in a more realistic scenario. I hope you enjoyed this write up, please check out the sample in github, and as always feel free to ask questions or show some love in the comments below.

More information / Download Fancy Transitions Sample code from Github

Reader comments

Weekend Coder: More custom UI's with Fancy Transitions

30 Comments
Sort by Rating

Not a coder nor do I know anything about it, but that White Z30 looks sweet! Prefer my black one but the white looks much nicer than I thought it would

Posted via my BlackBerry Q10 or Z30 on VZW from Philly

This is beautiful! And I saw the bottom bar is blue so... customization your own theme is coming in the next os update too?

Posted via CB10

Awesome piece of work. Cascade seems like fun!

Might dive right into it, if there wasn't that much stuff on my plate already.

iPhone for me? Scr... ahem Q that! (posted from the latter)

Thanks for continuing to do these write-ups Brian. Great information, and even a nice way to showcase what the coding can do!

BlackBerry 10 signed.

Wow I didn't even notice the animations API for Cascades. Some cool and powerful stuff! Thanks Brian, much appreciated.

The funny thing is there is nothing in this code that couldn't be done the day Cascades launched. I just think most devs haven't had a lot of experience with QML/Cascades yet so they haven't tried to get creative.

Posted via CB10

I could see how you would think that way, but I think that's mainly because QML has a lot of white space/line breaks in the code. It is possible to remove them all but then it is much harder to read in a tutorial setting.

If you check out the code on github I actually am able to separate the animations into separate custom reusable components that make the code extremely efficient.

Then as far as not having a built in swipe gesture I was trying my best to give a good user experience so I have some extra precautions in there.

Posted via CB10

Really awesome demo, Brian! I've been following this on twitter while you were working on it. I really appreciate you showing us how you do things like this and putting the code out there for all of us to experiment with! Thanks!

Nick

If anyone can implement this transition into the main OS launcher as an alternative to the existing one, I for one would definitely pay for it!

Posted via CB10