Flex has a lot of great facilities for styling and skinning, including custom scrollbars. Unfortunately, I’ve discovered that Flex really wants your vertical scrollbars to be 16 pixels wide. When it isn’t, Flex can make some strange layout decisions when first putting it on screen.
for example, check out this (very fancy) datagrid:
I made an 8-pixel wide vertical scrollbar, complete with a lovely red and purple coloring, and used it in my datagrid. Obviously, there’s a couple things wrong. First, there’s an ugly white gap between my content and my fancy scrollbar. Second, it looks like the content in my 2nd column has a different left padding than the content in my 1st column. Finally, the header area above the scrollbar didn’t render correctly.
To see what kind of scrolling behavior it had, I clicked on my “down arrow”:
A couple things sorted themselves out: the 8-pixel white gap is gone, the header looks right, and the content in the last row (Roger McBob) looks proper. As a final test, I sorted the 2nd column and got this:
Now all the content looks properly placed. So what the heck is going on here?
This bad behavior can be traced back to ScrollControlBase.as, in setScrollBarProperties() and createVScrollBar().
setScrollBarProperties() is going to be invoked from DataGrid’s updateDisplayList(). What we’re really interested in is whether the content area (for the first and last names) has changed size, which is tracked in the class variable scrollAreaChanged. If that scroll area has changed, then setScrollBarProperties() is going to call updateDisplayList().
What’s that? Aren’t we already in a call to updateDisplayList(), and isn’t that call going to re-execute DataGrid.updateDisplayList() and get us right back in here?
Yes. Yes it will.
The other thing that setScrollBarProperties() is doing is deciding whether or not it needs to create or destroy scrollbars. For the situation I’ve created, it will need to create a vertical scrollbar. And it does so with a call to createVScrollBar(). That new scrollbar, before its measure() can get called, is going to report a width of 16, which is the default. And that value will be used to determine not only the overall content area (c.f. that ugly white gap), but also how the content therein is placed (c.f. the 2nd column content being off a few pixels). It’s going to do all this before we can actually measure the scrollbar, even when we re-enter the method. It’s not until we start interacting with the control (scrolling, sorting) that we get back into setScrollBarProperties() after the scrollbar has finally been measured. As we can see, it then starts laying out properly.
It’s great that the framework handles getting us back into that method, but I can’t help thinking that it would be better served through an invalidation cycle, rather than a recursive call. If that happened, we’d go through a proper measure cycle and the content area would be sized correctly without having to touch the control.
Funnily enough, in createVScrollBar() (I’m looking at the Flex SDK 3.5 here), there’s this code:
Given the way the code is written now, I’d say the answer is yes. That would force a measure and our datagrid would render correctly the first time. Maybe that should have been explored more before simply commenting it out.