I've often wished Flex would simply shrink the available width of my
containers when their contents grow too tall, but alas, often you'll find yourself
with a horizontal scrollbar that only exists to show you the content that's just been
hidden by the vertical scrollbar that wasn't there a minute ago!
It's a common question, and the Adobe guys had
their reasons for making it how it is. Not much consolation for the rest of us though! So, a (perhaps not
the, but a) solution:
package info.joshmcdonald.barra.components
{
Shameless self-promotion: I've created a google code project for code examples and utils from my blog.
import flash.display.DisplayObject;
import mx.containers.Canvas;
import mx.core.UIComponent;
public class SmartVerticalScroll extends Canvas
{
override public function addChild(child : DisplayObject) : DisplayObject
{
return addChildAt(child, numChildren);
}
override public function addChildAt(child : DisplayObject, index : int) : DisplayObject
{
if (numChildren > 0)
throw new Error("Only one child, stick a canvas or something in here");
return super.addChildAt(child, index);
}
Just to keep thing simple, and this example small, we're limiting this to a single child. Not ideal, but we can
get away with it by simply using it as a container for a Canvas or a VBox or similar.
override protected function updateDisplayList(unscaledWidth : Number, unscaledHeight : Number) : void
{
var innerWidth : Number = unscaledWidth - borderMetrics.left - borderMetrics.right;
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (numChildren == 1)
{
var child : DisplayObject = getChildAt(0);
var uic : UIComponent = child as UIComponent;
if (uic)
{
if (verticalScrollBar)
{
var newWidth : Number = Math.max(Math.min(uic.width + uic.x , innerWidth - verticalScrollBar.width), uic.measuredMinWidth);
uic.setActualSize(newWidth, uic.height);
}
}
else
{
child.x = 0;
child.y = 0;
}
}
}
Here's where half the magic lies. If we have a vertical scrollbar, we'll shrink our child component to fit within it,
unless that would violate its minWidth requirement.
override public function validateDisplayList() : void
{
var before : Boolean = verticalScrollBar == null;
super.validateDisplayList();
var after : Boolean = verticalScrollBar == null;
if (after != before)
{
//Scrollbar added or removed - repaint and resize inner component
invalidateDisplayList();
}
}
}
}
Here's the other half of the magic. When we determine that Flex's built in layout code has decided to
add a vertical scrollbar, we make sure to schedule another call to our updateDisplayList() so we can
shrink the content down to get out of the way.