October 8th, 2007 by Kyle
Tags: ActionScript, Flex, mask, masking, menu, menubar, rounded-menu
Posted in: ActionScript, Flex
I had a customer that was trying to use masking to make menus appear with rounded corners. I had gotten this to work, but there was something I could not figure out that caused a flicker as menus were selected and appeared. I put this on the back shelf for a while and recently revisited it. To my surprise, the issue I had previously seen had gone away. Either something in the Flex framework had changed or a more recent version of the player had a beneficial effect. Whatever the cause, I decided it was good enough and that I should post this code.
In this sample, I extended the default MenuBar, so I could get a handle on new menus as they are shown to apply the mask. I also implemented a new style “corner-radius” and a custom menuItem renderer.
Browse the source of this example.
Download a zipfile containing the source to this sample.
Here is the code for the app:
<mx:application xmlns:mx="http://www.adobe.com/2006/mxml">
creationComplete="initCollections()" xmlns="*"
viewSourceURL="wp-content/code/Flex2.0.1hf2/739stl_RoundedMenus/srcview/index.html">
<mx:style>
MyMenuBar {
padding-top: 0; padding-left: 0; padding-right: 0;
padding-bottom: 0; border-thickness: 0; borderStyle: "none";
}
.MyMenuStyle {
corner-radius: 20;
padding-top: 0; padding-left: 0; padding-right: 0;
padding-bottom: 0; border-thickness: 0; borderStyle: "none";
}
</mx:style>
<mx:script>
<!–[CDATA[
import mx.controls.Alert;
import mx.collections.*;
[Bindable]–> public var menuBarCollection:XMLListCollection;
private var menubarXML:XMLList =
<>
<menuitem label="Menu1" data="top">
<menuitem label="MenuItem 1-A" key="1A">
<menuitem label="MenuItem 1-B" key="1B">
</menuitem>
<menuitem label="Menu2" data="top">
<menuitem label="MenuItem 2-A" key="2A">
<menuitem label="MenuItem 2-B">
<menuitem label="SubMenuItem 3-A" key="3A">
<menuitem label="SubMenuItem 3-B" key="3B">
</menuitem>
</menuitem>
</menuitem>;
private function initCollections():void {
menuBarCollection = new XMLListCollection(menubarXML);
}
]]>
</menuitem>
<mymenubar labelfield="@label">
dataProvider="{menuBarCollection}"/>
</mymenubar>
</menuitem></menuitem></menuitem></mx:script></mx:application>
Here is the code for the extension to the default menubar:
{
import mx.controls.MenuBar;
import mx.controls.Menu;
import mx.events.MenuEvent;
import flash.display.Sprite;
import mx.core.ClassFactory;
public class MyMenuBar extends MenuBar
{
public function MyMenuBar() {
super();
addEventListener("menuShow", onMenuShow);
}
override public function getMenuAt(index:int) : Menu {
var menu:Menu = super.getMenuAt(index);
menu.styleName = "MyMenuStyle";
menu.itemRenderer = new ClassFactory(MyMenuItemRenderer);
menu.setStyle("openDuration",0);
menu.cacheAsBitmap=false;
return menu;
}
private function onMenuShow(e:MenuEvent):void{
callLater(maskRoundedCorners,[e]);
}
private function maskRoundedCorners(e:MenuEvent):void{
var menu:Menu=e.menu as Menu;
menu.cacheAsBitmap=false;
if (!menu.mask){
var maskx:uint = menu.x;
var masky:uint = menu.y;
var maskw:uint = menu.getExplicitOrMeasuredWidth();
var maskh:uint = menu.getExplicitOrMeasuredHeight();
var rad:int = menu.getStyle("cornerRadius") * 2;
var roundRect:Sprite = new Sprite();
roundRect.graphics.beginFill(0xFFFFFF);
roundRect.graphics.drawRoundRect(maskx,masky,maskw,maskh,rad);
roundRect.graphics.endFill();
menu.mask = roundRect;
}
}
}
}
Here is the code for the custom menuItemRenderer:
<mx:hbox xmlns:mx="http://www.adobe.com/2006/mxml">
implements="mx.controls.listClasses.IListItemRenderer,
mx.controls.menuClasses.IMenuItemRenderer,
mx.controls.listClasses.IDropInListItemRenderer"
horizontalScrollPolicy="off">
<mx:script>
<!–[CDATA[
import mx.controls.Alert;
import mx.controls.menuClasses.IMenuDataDescriptor;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.ListData;
import mx.controls.Menu;
import mx.controls.menuClasses.MenuBarItem;
private var _menu:Menu;
private var _listData:ListData;
private var lblText:String;
private var keyText:String;
private var isBranch:Boolean;
override public function set data(value:Object) : void {
super.data = value;
this.lblText = this.data.@label;
this.keyText = this.data.@key;
var dataDescriptor:IMenuDataDescriptor =
Menu(_listData.owner).dataDescriptor;
this.isBranch = dataDescriptor.isBranch(super.data);
invalidateProperties();
invalidateSize();
}
public function get menu() : Menu {
return _menu;
}
public function set menu( value:Menu ) : void {
_menu = value;
}
public function get listData() : BaseListData {
return _listData;
}
public function set listData( value:BaseListData ) : void {
_listData = ListData(value);
invalidateProperties();
}
override public function setActualSize(w:Number, h:Number) : void {
super.setActualSize( Menu(_listData.owner).width, h );
}
override protected function commitProperties() : void {
super.commitProperties();
// Branch icon
if ( isBranch ) {
arrow.visible=true;
arrow.includeInLayout=true;
}
else{
arrow.visible=false;
arrow.includeInLayout=false;
}
lbl.text=lblText;
key.text=keyText;
}
]]–>
</mx:script>
<mx:label id="lbl">
width="100%"
textAlign="left"
paddingLeft="8"
paddingRight="6"/>
<mx:label id="key">
minWidth="30"
paddingRight="10"
textAlign="right"
fontStyle="italic" />
<mx:image id="arrow" width="20" source="@Embed(source=’Assets.swf’,symbol=’MenuBranchEnabled’)">
visible="true" />
</mx:image>
</mx:label></mx:label></mx:hbox>











March 14th, 2008 at 2:41 am
Under the current SDK the above code tosses:
Interface method get measuredBranchIconWidth in namespace mx.controls.menuClasses:IMenuItemRenderer not implemented by class MyMenuItemRenderer.
Adding:
override public function get measuredBranchIconWidth():Number {}
tosses:
1020: Method marked override must override another method.
March 14th, 2008 at 8:52 am
Have since found the correct syntax on the overrides:
public function get measuredBranchIconWidth():Number { return 10;}
Sure appreciate the time taken to post this sample. Seems to be surprisingly few menuItemRenderer samples out here.
March 14th, 2008 at 9:17 am
I am glad you found the fix. I haven’t looked at this sample since I wrote it for the 2.0 code base.
July 18th, 2008 at 2:48 am
hello, how to change the backgroundcolor of the rolloutitems? i cant find anything for changing the white color. its urgent
July 21st, 2008 at 5:48 am
change the xml to following. The code throws a run time exception. Do you know why?
private var menubarXML:XMLList =
;
July 21st, 2008 at 5:51 am
Sorry the xml is not attached. Basically if the xml only has one composite menu items, the code will fail
private var menubarXML:XMLList =
menuitem label=”Menu1″ data=”top”
menuitem label=”MenuItem 1-A” key=”1A”
menuitem label=”MenuItem 1-B” key=”1B”
menuitem
August 11th, 2008 at 2:52 pm
Do you have any recommendations or can you point me in the right direction in terms of further customizing the menuBar component. There doesn’t seem to be a lot of information available, and I’m having trouble when it comes to styling disabled menu items and other conditional cases of items in the list. Any help would be appreciated. Thanks. Great site.
September 22nd, 2008 at 4:23 am
You can set style of Menu…color, rollOverColor, SelectionColor, TextRollOverColor will help you.