12-17-2010 07:06 AM
Hello everybody,
In one of the nice videos about the tablet, I saw some kind of system menu which could be used by any app to put menu items in it, to keep thew main window design clear.
Does anybody know how to accomplish this? My intension is to put some items like "configuration" and "about" to not overload my main UI.
Thanks in advance
Marco
Solved! Go to Solution.
12-17-2010 07:15 AM - last edited on 12-17-2010 11:18 AM
hey germama,
in the webcast's they recommended that we not put any "title bars" in our apps to save space for content. so what they recommended was that we use a optional menu to be "dragged" out of hiding from the top of the playbook. you can go to this video and see it in action and see some source code (a glimpse really) here:
http://2010.max.adobe.com/online/2010/MAX260_12882
if you go to about 13:45 minutes into the presentation they start talking about the menu. after you get a good idea, take a look at the code below and see if you can kind of get an idea about how to approach this:
SwipeDownTest.as (Main application file):
package
{
import caurina.transitions.Tweener;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import qnx.events.QNXApplicationEvent;
import qnx.system.QNXApplication;
// The following metadata specifies the size and properties of the canvas that
// this application should occupy on the BlackBerry PlayBook screen.
[SWF(width="1024", height="600", backgroundColor="#CCCCCC", frameRate="30")]
public class SwipeDownTest extends Sprite
{
private var ui:UI;
public function SwipeDownTest()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
ui = new UI();
addChild(ui);
QNXApplication.qnxApplication.addEventListener(QNX ApplicationEvent.SWIPE_DOWN, onSwipeStart);
}
private function onSwipeStart( e:QNXApplicationEvent ):void
{
stage.addEventListener( Event.ENTER_FRAME, showNavigation );
}
private function showNavigation( e:Event ):void
{
Tweener.addTween(ui, {y: 0, time: .3, transition: "linear"});
stage.removeEventListener(Event.ENTER_FRAME, showNavigation);
stage.addEventListener(MouseEvent.CLICK, hideNavigation);
}
public function onMouseUp(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.CLICK, hideNavigation);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
public function hideNavigation(e:MouseEvent):void
{
if (stage.mouseY > 123)
{
Tweener.addTween(ui, {y: -123, time: .3, transition: "linear"});
stage.removeEventListener(MouseEvent.CLICK, hideNavigation);
}
}
}
}
UI.as (Navigation bar class):
package
{
import flash.display.Shape;
import flash.display.Sprite;
public class UI extends Sprite
{
private var navBar:Shape;
public function UI()
{
//set it up with two sections
navBar = new Shape();
navBar.graphics.beginFill(0x333333, 1);
navBar.graphics.drawRect(0,0,1024,123);
navBar.graphics.endFill();
this.y = -123;
addChild(navBar);
}
}
}
i tried to mimic their menu as best as i could and thats the result. it involves the application listening to the SWIPE_START event and then proceed with showing a menu. the example is very crude but it gets hte point across. hope that helps! good luck!
EDIT: Modified both AS files due to some odd errors. new code should work without a hitch. sorry about that. thanks for the pointing it out peter!
12-17-2010 07:16 AM
React to this event:
Show your menu, or about screen or configuration, anything. This event informs application that user has done top down swipe starting from top bezel (the only one bezel swipe to which app has access). Search the forum to know how to use Tweener to give your app nice screen flow.
12-17-2010 08:13 AM
Thank you very much for the quick reply! This helped alot!
12-17-2010 10:16 AM
JRab wrote:
i tried to mimic their menu as best as i could and thats the result. it involves the application listening to the SWIPE_START event and then proceed with showing a menu. the example is very crude but it gets hte point across.
J.Rab, does that example actually work fully for you? One my simulator, I can drag down nicely, but when I release the mouse button it doesn't "roll up" again. Instead I have to press the mouse button down and then release again before it registers.
Basically it's missing the first mouse up, possibly (wild guess) because the original mouse down wasn't within the area of the stage, but was up in the bezel. Just wondering if it works properly for anyone other than me.
12-17-2010 11:16 AM
hey peter,
thanks for catching that bug. wats weird is that the code was working perfectly for me before. maybe the new sdk changed something and things happen a little differently. either way i changed the code to work now. here is the modified code:
SwipeDownTest.as (Main application class):
package
{
import caurina.transitions.Tweener;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import qnx.events.QNXApplicationEvent;
import qnx.system.QNXApplication;
// The following metadata specifies the size and properties of the canvas that
// this application should occupy on the BlackBerry PlayBook screen.
[SWF(width="1024", height="600", backgroundColor="#CCCCCC", frameRate="30")]
public class SwipeDownTest extends Sprite
{
private var ui:UI;
public function SwipeDownTest()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
ui = new UI();
addChild(ui);
QNXApplication.qnxApplication.addEventListener(QNX ApplicationEvent.SWIPE_DOWN, onSwipeStart);
}
private function onSwipeStart( e:QNXApplicationEvent ):void
{
stage.addEventListener( Event.ENTER_FRAME, showNavigation );
}
private function showNavigation( e:Event ):void
{
Tweener.addTween(ui, {y: 0, time: .3, transition: "linear"});
stage.removeEventListener(Event.ENTER_FRAME, showNavigation);
stage.addEventListener(MouseEvent.CLICK, hideNavigation);
}
public function onMouseUp(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.CLICK, hideNavigation);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
public function hideNavigation(e:MouseEvent):void
{
if (stage.mouseY > 123)
{
Tweener.addTween(ui, {y: -123, time: .3, transition: "linear"});
stage.removeEventListener(MouseEvent.CLICK, hideNavigation);
}
}
}
}
UI.as (Navigation Class):
package
{
import flash.display.Shape;
import flash.display.Sprite;
public class UI extends Sprite
{
private var navBar:Shape;
public function UI()
{
//setup the "nav bar"
navBar = new Shape();
navBar.graphics.beginFill(0x333333, 1);
navBar.graphics.drawRect(0,0,1024,123);
navBar.graphics.endFill();
this.y = -123;
addChild(navBar);
}
}
}
it works a little differently but gets the job down. lemme know if this works for you. again thanks! good luck!
12-17-2010 02:16 PM - last edited on 12-17-2010 02:56 PM
At first I thought that didn't work at all, but that's just because I was using debug mode and timer-based stuff (setTimeout, Timer, or enter_frame events) never works when I'm doing that for some reason.
I played a bit and got the following working too, which I think is closer to what you were trying to do before. This more closely mimics the system menu. I used roughly the same Y value as SWIPE_DOWN triggers at. If you release the mouse when still above that the menu retracts, but if you're below it locks it into position.
Sliding the menu back up is considered an app-specific behaviour here... maybe you want to just click below it, but maybe some other behaviour is better for you... depends on what you have in the menu.
package
{
import caurina.transitions.Tweener;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.Sprite;
import qnx.events.QNXApplicationEvent;
import qnx.system.QNXApplication;
[SWF(height="600", width="1024", frameRate="30", backgroundColor="#cccccc")]
public class MenuTest extends Sprite
{
private var ui:UI;
private var swiping:int;
// rough numbers eyeballed from system menu
public const SWIPE_REGION:int = 23;
public const MENU_HEIGHT:int = 62;
public function MenuTest()
{
ui = new UI(stage.stageWidth, MENU_HEIGHT)
addChild(ui);
QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_START, swipeMenu);
stage.addEventListener(MouseEvent.MOUSE_DOWN, swipeMenu);
stage.addEventListener(MouseEvent.MOUSE_UP, swipeMenu);
}
private function swipeMenu(e:Event):void
{
if (e.type == QNXApplicationEvent.SWIPE_START)
{
trace("prepare to swipe");
swiping = 1;
}
else if (e.type == MouseEvent.MOUSE_UP)
{
if (swiping == 2)
{
if (stage.mouseY >= SWIPE_REGION)
{
function now_showing():void {
trace("menu now visible");
// in real code could be a method on the class
}
Tweener.addTween(ui, {y: 0, time: .3, transition: "linear",
onComplete: now_showing});
}
else
{
trace("swipe cancelled");
Tweener.addTween(ui, {y: -MENU_HEIGHT, time: .3, transition: "linear"});
}
// either way, we're done swiping
stage.removeEventListener(Event.ENTER_FRAME, swipingMenu);
swiping = 0;
}
}
else if (e.type == MouseEvent.MOUSE_DOWN)
{
if (swiping == 1)
{
trace("swiping");
swiping = 2;
stage.addEventListener(Event.ENTER_FRAME, swipingMenu);
}
}
}
private function swipingMenu(e:Event):void
{
var y:int = stage.mouseY >= MENU_HEIGHT ? MENU_HEIGHT : stage.mouseY;
ui.y = y - MENU_HEIGHT;
trace(e, y);
}
}
}
import flash.display.Shape;
import flash.display.Sprite;
import qnx.ui.text.Label;
class UI extends Sprite
{
public function UI(width:int, height:int)
{
var navBar:Shape = new Shape();
navBar.graphics.beginFill(0x333333, 1);
navBar.graphics.drawRect(0, 0, width, height);
navBar.graphics.endFill();
var title:Label = new Label();
title.text = "App Menu";
title.y = (height - title.textHeight) / 2;
this.y = -height;
addChild(navBar);
addChild(title);
}
}
That's all in one file for ease of use...
It occurs to me that we maybe shouldn't be thinking of these in the same way as drop-down menus in desktop operating systems (i.e. where you get a vertical selection of choices as you wave the mouse around). Here we probably are getting more like a panel of choices with buttons, ala the Navigator's system menu.
(Edited: The code is now what I initially had, before I simplified for posting and didn't test adequately. This one uses a small state machine to ensure that you are still holding the mouse button down. The previous one may work okay on the tablet, but this one is required for use with a mouse. Otherwise you can click-and-release on the bezel, then see the menu being dragged down as you move the mouse down even though you aren't holding the mouse button down. Yet another case where not having a real tablet makes testing difficult.)
12-17-2010 03:24 PM
peter9477 wrote:This more closely mimics the system menu.
Maybe "more closely" but not perfectly, yet.
I just noticed that the system menu actually pushes the contents of the screen down as it comes down, whereas the latest menu code above slides down over the content.
There's other interesting differences that I've discovered now that I've also found how to show the system menu while in an application. I haven't seen it reported elsewhere yet, but -- similar to the swipe-from-lower-left-bezel gesture to show the keyboard -- you can swipe from either upper corner to show the system menu at any time.
Actually it's not even necessary to move in from the corner, as there seems to be a region that extends about 50 pixels into area above the screen where you can swipe from. That means the swiping region for your application menu is only about 924 pixels wide, not the full 1024.
I also think I've discovered what the SWIPE_DOWN event is used for, at least in the case of the system menu. If you swipe slowly down in Navigator (the thing that launches your apps) from the top bezel, you'll see that around Y=23 or so the System Menu suddenly extends down to cover the entire screen. (You'll see the content corresponding to whatever widget you have most recently clicked on in the menu bar.)
Interestingly, this SWIPE_DOWN event doesn't appear to be used when you use the corner areas to swipe into an application. Instead you have to drag about a third of the way down the screen before the menu will take over the screen. Release anywhere above that and it rolls itself back up like a window blind.
My guess is we'll see many tweaks in all this before release. ![]()
12-18-2010 02:25 AM
I'm new t developing applications and I am building a playbook app in adobe flex and was wondering if there is a way to implament this code in flex. When I try to import the qnx.events.QNXApplicationEvent it says the namespace was not found
12-22-2010 01:15 PM
osuthorpe wrote:
I'm new t developing applications and I am building a playbook app in adobe flex and was wondering if there is a way to implament this code in flex. When I try to import the qnx.events.QNXApplicationEvent it says the namespace was not found
I am struggling with the same thing. I have added
QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_START, onSwipeStart);
to my "sudo" init function (there is no init function in flex --- but I have the creationComplete event of the view run a custom init() and it is throwing
VerifyError: Error #1079: Native methods are not allowed in loaded code.
at run time.
I am wondering if anyone managed to get this working in Flex...