Extending ScrollControlBase: Its Internals and Design Philosophy
This article is a 4-post series on extending ScrollControlBase. This post discusses how ScrollControlBase works internally, specifically how masks work, and what ScrollControlBase does, and doesn’t do, for subclasses. Here’s some links to the other posts in this article:
1. Its Internals and Design Philosophy
2. Displaying the Scrollbars
3. Getting Scrolling to Work
4. The Workflow
ScrollControlBase is one of those mystery classes that does a shitton of actual work, but isn’t mentioned much at all in the API documentation (Aside from the ScrollControlBase Reference, of course). That’s probably because it’s not intended to be used directly, but rather subclassed (Like ListBase, TileBase, and all the other Bases)
The problem is that I need to extend ScrollControlBase to implement a special kind of behavior: Vertically aligned content so that it appears from the bottom up, like in IRC clients, and some chat windows. I managed to do it with regular text by extending TextArea, but now I need to do it with an HTML element, and extending HTML didn’t work for me, so I decided to extend ScrollControlBase to build the functionality in directly. While I was at it, I wrote up what ScrollControlBase actually does for you, and the workflow needed to extend ScrollControlBase properly:
The Design of ScrollControlBase
ScrollControlBase is not a container, as it is intended to be subclassed. This has a few implications: Firstly, ScrollControlBase does not work via composition; it does not take some .content parameter that’s your content and magically positions it. Rather, it does no drawing of your content at all. It draws the scrollbars, any provided border, and exposes an interface to set their position. It displays the scrolled content accurately via a mask.
Understanding Masks
What a mask does is fairly simple. For the visual people, imagine a piece of paper, with the center cut out. Placing that paper on top of some image, or some article “masks” the rest of the image, showing only a portion. Now, for computers, this mask isn’t the paper, but the shape of the cutout. So if you cut out a circle, the mask you’d use would be a rendered circle. Every display object in flash has a mask property that accepts any display object, and those two are used together to render some image.
If you’re interested in how masks work at a technical level, read on. Otherwise, just skip this section:
For those more mathematically oriented, imagine two values in binary. The first value is 11110000, or four ones followed by four zeros. The second is 00111100, or four ones, with four zeros evenly divded on either side. Apply the bitwise & operation (which returns the value where both values are true in that location, 1 & 1 is 1, 0 & 0 is 0, along with 1 & 0, and 0 & 1). The bitwise & applied to our two values returns 00110000. At a bitwise level, a mask is just using & creatively, and neither value is inherently a mask or not.
At a higher level, the mask is usually itself some primitive image. Typically, all of a mask’s values are used to produce the derivation. That is, a black image masked over some source image, would produce an image the shape of the mask, with the image coming from the source. That’s of course not to say that some specific color channel couldn’t be used as the mask, producing the images showing only the reds, greens, or blues in some image.
For further information, check out this post on masks specifically in Flash and their various uses
What ScrollControlBase doesn’t do
ScrollControlBase, as previously mentioned, only draws a mask over its children, and adds interface to support scroll bars, positions, and adding a border. It doesn’t manipulate the position, or size, of the content it contains.
That ScrollControlBase has no default scrolling behavior could be construed as a weakness, since ScrollControlBase could directly manage the position of its content, and not have to have subclasses do it. However, that would mean that the subclasses would have to have their content fully rendered*. For very long lists, this would be very expensive to do. Instead, it lets children build in their own optimizations, like in the case of ListBase, which recycles its renders; as you scrol through the list, fully occluded renders are added to a freed list, and used to display the content coming up from the bottom. This allows list implementations to be as inexpensive as possible, since everything is done just in time.
*One could argue that the list being rendered could just give a filler for the content not exposed, allowing ScrollControlBase to still function as normal. This would work, but you’re still having to recycle renderers to gain the same level of functionality, so you’re not saving yourselves much as far as work needed to do to draw your list. I’d assume Flex developers figured each implementation would differ greatly enough in its optimziation that providing a default way would be too ambiguous to be useful.
Read on to see how to actually implement a sublcass of ScrollControlBase.
Leave a Comment