Flex/Flash/Actionscript

Even Better Scrollable Menus for Flex

Here’s an update to the Flex Scrollable Menu controls that I posted earlier today. Josh Tynjala made the point that he would rather have up and down arrows at the top and bottom of the menus to allow you to scroll without using a scrollbar on the side. Well, ok, ok, here you go. Now the menus can have either a vertical scrollbar on the side, rollover arrows on the top and bottom, or both! Yay!

Also, if you don’t specify a maxHeight for the controls, then the menus get sized as high as they can without going off the stage. So if a menu is too big it will size itself to as high as it can, and then start scrolling. If you specify the maxHeight attribute for the controls then the menu will try to size itself that high, but not higher. But again, if there’s not enough room on the stage then the menu won’t grow beyond the visible area. As far as I can figure, this is how menus should work.

So check it out and play with some of the options in the example. You can set both verticalScrollPolicy and a new property: arrowScrollPolicy. Both work the same way as you’d expect. arrowScrollPolicy controls the display of the up/down arrows just like the scrollbar is controlled. So you can set arrowScrollPolicy to ScrollPolicy.ON, ScrollPolicy.AUTO, and ScrollPolicy.OFF. If you turn both the arrows and the scrollbar on then you can scroll using either of them.

And again, full source is here.

This movie requires Flash Player 9.

Standard
Flex/Flash/Actionscript

Scrollable Menu Controls

As I was writing some stuff for the extended TabNavigator component that I’ve been working on (see some previous posts), I came across a need to use a PopUpMenuButton to list all the tabs, similar to how Firefox does this with the drop down list to the right of the tabs. This works great, except when there are a ton of tabs and the list gets really really long. Suddenly I realized that all the Menu controls in Flex have no option of adding a scrollbar to the menus. So if your menu is huge and goes off the stage, there’s nothing you can do about it and the menu items at the bottom are completely inaccessible.

mx.controls.Menu
So the complete inability to scroll a menu seemed a little weird to me, so I investigated and took a look into the mx.controls.Menu class. The answer to why the menus would never scroll is pretty obvious once you look at the code for the Menu control. The getter and setter for verticalScrollPolicy are these:


override public function get verticalScrollPolicy():String {
	return ScrollPolicy.OFF;
}

override public function set verticalScrollPolicy(value:String):void {
}

So if you were to try to set the verticalScrollPolicy of a Menu to ScrollPolicy.ON or ScrollPolicy.AUTO it wouldn’t do anything, and the scrollbars would remain off. There are a few other pieces in the code for Menu that don’t allow scrollbars, particularly in the configureScrollBars() and measure() methods.

So that’s no good if you want to allow scrollbars on your menus. The solution? An extension of mx.controls.Menu that overrides these problematic parts of the code. Basically I re-instituted the normal functionality for the getter and setter for verticalScrollPolicy, changed the configureScrollBars() method to actually configure the scrolling, and then modified measure() to take the scrollbars and new height restriction into account. Then we’ve got a new ScrollableMenu class that will allow you to set the maxHeight property. If the menu goes beyond maxHeight then the scrollbars are added, just like a normal scrolling control.

mx.controls.MenuBar
I also created a class that extended the MenuBar class, so it would use my new ScrollableMenu instead of the normal Menu when it created the Menus for the MenuBar. I was able to keep this extension fairly short, mostly just with an override of getMenuAt() and a private menu event listener.

So com.dougmccune.controls.ScrollableMenuBar lets you use the MenuBar control and specify a maxHeight, which will put a height limitation on the menus that popup when you click a menu item.

mx.controls.PopUpMenuButton
The PopUpMenuButton class was trickier. I initially tried to do a simple extension and get it to use the ScrollableMenu class instead of the normal Menu class, but this didn’t work so well. This was one of those cases (I’ve encountered this quite a bit) where the class you’re extending has private functions and variables that you need access to in order to accomplish your goals. I really didn’t need to make many changes to PopUpMenuButton, but because of the structure of the class I simply wasn’t able to make a clean extension.

So instead of extending PopUpMenuButton I had to copy/paste the entire class into a new class, and make the changes I needed. I’ve had to do this quite a few times to get custom components that I need. It’s obviously not ideal, you end up bloating your code base, but sometimes that’s the only option. But in the end we have a ScrollablePopUpMenuButton class that allows us to specify a maxHeight and that height will apply to all menus and submenus.

I’ve included the full source of all of these classes and the example below. I documented the code pretty well, so hopefully you can figure it out by taking a look. I wasn’t planning on uploading this one to Adobe Exchange, it doesn’t seem quite “componenty” enough. But if someone from Adobe thinks it belongs on the exchange then I’ll upload it, let me know in the comments.

View the source. UPDATE: See the next post for the current source of the component.

Here’s the example:

This movie requires Flash Player 9.

Standard