Home >
Flash Player's display API offers three different tools for hiding display
objects from the screen: the visible variable, the
alpha variable, and the removeChild() method. All
three tools achieve the same end result—hiding a graphic—but each tool serves
a different structural need. Hence, there is no single answer to the question
"Should I hide graphics with visible, alpha, or
removeChild()?" Instead,
developers must choose the approach that suits the task at hand based on a
variety of factors. Before we consider those factors, let's take a look at
visible, alpha, and removeChild() in
action.
First, let's create two Sprite objects and assign them to two variables,
background and ball:
// A background rectangle
var background:Sprite = new Sprite();
background.graphics.beginFill(0x656600);
background.graphics.lineStyle(6);
background.graphics.drawRect(0, 0, 400, 300);
// A circular "ball" graphic
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0xDFDA98);
ball.graphics.lineStyle(6);
ball.graphics.drawCircle(0, 0, 40);
Next, let's move ball over a bit:
ball.x = 275;
ball.y = 100;
Now we'll make ball a display child of
background:
background.addChild(ball);
And, finally, we'll place background on the display list.
Assume, for this example, that mainCanvas refers to a Sprite that
is already on the display list:
mainCanvas.addChild(background);
Figure 1 shows the result of the preceding code.
Figure 1. The background and ball objects.
Now let's consider three different ways to hide ball from the
screen. First, we could set visible to false, as
follows:
ball.visible = false;
Or, we could hide ball by setting alpha to 0, as
follows:
ball.alpha = 0;
Finally, we could hide ball by removing it from the display list
entirely, as follows:
background.removeChild(graphic);
In all three cases, ball is hidden from view. However, in the
first two cases (using visible and alpha), even though
ball is removed from the screen, it remains a child of the
background container. By contrast, in the final case (using
removeChild()), ball is both removed from the screen
and removed from the background container object. That
structural distinction is an important difference to consider when choosing
between visible, alpha, and
removeChild().
Choosing Between visible, alpha, and removeChild()
When deciding whether to use visible, alpha, or
removeChild() in an application, developers should consider the
following factors.
In the remainder of this article the term "non-visible" refers to an object hidden via thevisiblevariable. The term "zero-alpha" refers to an object hidden via thealphavariable.
Factor 1: Non-visible children stay in the stacking order
For the first factor, let's revise our ball example so that
instead of placing ball inside background, we place
both background and ball directly inside
mainCanvas. Here's the revised code:
// A background rectangle
var background:Sprite = new Sprite();
background.graphics.beginFill(0x656600);
background.graphics.lineStyle(6);
background.graphics.drawRect(0, 0, 400, 300);
// A circular "ball" graphic
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0xDFDA98);
ball.graphics.lineStyle(6);
ball.graphics.drawCircle(0, 0, 40);
ball.x = 275;
ball.y = 100;
// Add background to mainCanvas, below ball
mainCanvas.addChild(background);
// Add ball to mainCanvas, above background
mainCanvas.addChild(ball);
visible and
removeChild() in an example. Suppose we're making an application where the ball graphic from the preceding code must always appear on top of the
background graphic, and the background must sometimes
be hidden. Because the preceding code already adds background to mainCanvas
before ball, background automatically appears behind
ball. Hence, to "sometimes hide" background, we can
simply toggle background.visible between true and
false. Any time background reappears, it is correctly
stacked behind ball. The methods required to hide and show
background are as follows:
public function hideBackground ():void {
background.visible = false;
}
public function showBackground ():void {
background.visible = true;
}
By contrast, if we were to use removeChild() to hide
background, then background would be removed from
mainCanvas's stacking order. When showing background
again, we would need to carefully re-add background at the correct
depth behind ball (using addChildAt(), not
addChild()). The required hide and show methods would be as
follows:
public function hideBackground ():void {
// Use an instance variable, oldBackgroundDepth, to
// remember background's depth
oldBackgroundDepth = mainCanvas.getChildIndex(background);
mainCanvas.removeChild(background);
}
public function showBackground ():void {
mainCanvas.addChildAt(background, oldBackgroundDepth);
}
In the preceding scenario, the stack-management code required in the removeChild() implementation makes the removeChild() approach more cumbersome
to implement and maintain than the visible approach.
Factor 2: 'visible = false' executes faster than removeChild()
Hiding a graphic by setting visible to false is faster than hiding it with
removeChild(). The difference in speed is negligble, but could
be a factor in a demanding application. In testing, setting a display object's
visible variable proved to be approximately 43 times faster than
calling addChild() or removeChild() on the same
object. In Flash Player 9, on an 8-core Mac Pro running Windows Vista, 10000
removeChild() calls took 300ms, whereas 10000 visible
assignments took 7ms.
Factor 3: Non-visible and removed children have no rendering cost
From a rendering-performance perspective, there is no practical difference
between the removeChild() and visible=false
approaches. In both cases, the renderer completely skips rendering any removed
or non-visible objects. By contrast, objects with alpha set to 0 do
have a minor rendering cost. Consider the following test results, which show the
time required to render a single frame in an application containing 1000 instances
of a complex vector shape. In the test, Flash Player was set to 24 frames per
second, or approximately one frame every four milliseconds.
Children on the Single-frame
Display List .visible .alpha Elapsed Time (ms)
No Children 0 -- -- 4
Non-visible 1000 false 1 4
Zero Alpha 1000 true 0 85
Fully Visible 1000 true 1 1498
90% Transparent 1000 true .1 1997
In the preceding results, notice that the time to render a frame with no
children was exactly the same as the time to render a frame with 1000
non-visible children. However, the time to render a frame with 1000 zero-alpha
children was 81ms longer than the time to render a frame with 1000 non-visible children—proving that
objects with alpha set to 0 have a minor rendering cost. With all
children completely visible, the cost of rendering naturally increases, up to
1498ms in the test. And, of course, rendering 1000 partially visible children
took the longest, at 1997ms. In relative terms, rendering transparent,
overlapping objects is an expensive operation.
Factor 4: Non-visible children affect parent dimensions
Suppose a container, box, has a single child, icon:
box.addChild(icon);
Assuming box has no other content, if icon's width
is 50, box's width will also be 50:
trace(icon.width); // 50
trace(box.width); // 50
And even when icon's visible variable is set to
false, box's width, perhaps suprisingly, remains
50:
icon.visible = false;
trace(box.width); // Still 50! (Despite the fact that
// box appears empty on screen.)
The discrepancy between box's on-screen appearance and its
programmatic dimensions affects layout and collision code in the application.
For example, when icon is non-visible, any layout code that wishes
to position graphics around box based on box's
on-screen visible size must manually ignore icon's dimensions:
// Place a button to the right of box.
button.x = box.x + box.width;
if (icon.visible == false) {
button.x -= icon.width;
}
Here's a tighter way to write the preceding code:
// Place a button to the right of box.
button.x = box.x + box.width - (!icon.visible ? icon.width : 0);
By contrast, if icon is hidden via removeChild()
rather than visible, then box's
width becomes 0, which intuitively matches its on-screen appearance.
box.removeChild(icon);
trace(box.width); // 0
Once icon is removed, layout code can trust box's
reported dimensions when positioning graphics, without any special "ignore
non-visible children" conditions:
// Place a button to the right of box.
button.x = box.x + box.width; // Much nicer...
In a layout engine, recursivley checking containers for non-visible children is cumbersome and slow. I've filed a bug requesting that Adobe address this issue by introducing a flag to exclude non-visible children in parent-bounds calculations. Please vote for the bug if you're affected by this issue.
Factor 5: Non-visible children can get in your way
Imagine you're creating a container, optionsPane, with 100
checkboxes as children. At any given time, 10 of the checkboxes are shown on
screen and 90 have visible set to false. To determine
which checkboxes are checked, your program loops over optionsPane's
children:
var results:Array = new Array();
for (var i:int = 0; i < optionsPane.numChildren; i++) {
if (CheckBox(optionsPane.getChildAt(i)).checked) {
results.push(true);
} else {
results.push(false);
}
}
But the preceding code returns the results for all 100 checkboxes, not just
the visible ones. To determine which visible checkboxes are checked, the
loop must conditionally "step over" any checkbox whose visible
variable is false:
var results:Array = new Array();
var child:DisplayObject;
for (var i:int = 0; i < optionsPane.numChildren; i++) {
child = optionsPane.getChildAt(i));
if (CheckBox(child).checked && child.visible) {
results.push(true);
} else {
results.push(false);
}
}
removeChild() instead of visible to hide the
checkboxes, the loop wouldn't need to "step over" non-visible checkboxes.
Factor 6: Objects with alpha set to 0 receive mouse events
Unlike objects with visible set to false, objects
with alpha set to 0 are considered interactive, and can receive
mouse events. For example, if you place your mouse pointer over a zero-alpha
object, Flash Player dispatches a MouseEvent.MOUSE_OVER event targeted at that
object. Zero-alpha objects, hence, can be useful for creating non-visual
elements that capture user input, such as "invisible buttons" or "easter eggs."
General Guidelines to Follow
With the preceding factors in mind, let's look at a few guidelines to follow
when deciding between visible, alpha, and
removeChild(). The following strategies are particularly useful in
visual applications that repeatedly toggle graphics between visible and hidden
states.
Recommendation 1: Use removeChild() for predictability
When in doubt, use removeChild() instead of visible
because using visible can produce misleading parent dimensions. See
Factor 4. Particularly avoid visible when visual dimensions matter,
such as when testing for collisions in a game or when arranging graphics
programmatically. Note that this recommendation would be made obsolete if Adobe
were to address Flash Player
Bug 741.
Recommendation 2: Use visible for performance and convenient depth management
When speed and stacking order are your key concerns, use visible
instead of removeChild() because setting visible is
faster than calling removeChild() (see Factor 2), and using
visible facilitates easy depth management (see Factor 1). But be
careful when working with dimensions in layout and collision code (see Factor
4). Furthermore, remember that even in applications that use
visible to hide graphics, when a graphic is no longer needed, it
should be removed from its parent container via removeChild(), and
then dereferenced so it can be garbage collected. See the section "Not visible
does not mean deleted", below.
Recommendation 3: Generally avoid alpha
Avoid using alpha to completely hide graphics because zero-alpha
graphics take longer to render than both non-visible graphics and removed
graphics. See Factor 3 and Factor 6. Hide graphics with alpha only
when creating interactive hidden-graphics.
Related Considerations
When removing graphical assets from the screen, bear in mind the following
issues, which are important regardless of whether you're using
visible, alpha, or removeChild().
Not visible does not mean deleted
Setting an object's visible to false or
alpha to 0 does not remove that object from memory.
Likewise, removing an object from the display list via
removeChild() does not remove that object from memory. Display
objects are removed from memory only once they have been deactivated, dereferenced,
and garbage collected. Regardless of your application's visibility strategy,
be sure to deactivate and dereference your display objects when they are no
longer needed.
Off-screen MovieClip timelines can be hazardous
Suppose you have an on-screen MovieClip object whose timeline is playing. If
you hide that MovieClip using visible, alpha, or
removeChild(), its timeline will continue to play. As the timeline plays, it will have several negative side-effects:
- The timeline playback will consume system resources.
- If the playhead advances to a frame with code, that code will execute, potentially wasting system resources and triggering undesirable program side-effects.
- If the MovieClip object's visual contents change when a new frame is reached, the object's dimensions will also change, potentially affecting parent dimensions (see Factor 4).
Therefore, as a general rule, remember to stop the playback of all MovieClip objects that are not on screen.
Thus ends our examination of visibility management in ActionScript. Hopefully it has helped you navigate some of ActionScript's subtler display-programming issues. My thanks to Jim Corbett, lead engineer on Flash Player's display API, who fielded my research questions during the writing of this article.
Happy coding!




Facebook Application Development
Very interesting and useful. Do you know if the time taken to render zero alpha objects exists because of the events they can still receive? I.e. would 1000 mouse disabled objects still consume as much render time?
Another approach, and a favourite of mine, is the following:
<mx:Panel>
<mx:Button label="b1"
id="b"
visible="{someCondition}"
includeInLayout="{b1.visible}"/>
<mx:Button label="b2"/>
</mx:Panel>
...
This makes the panel resize itself and move b2 according with no need to manually calculate anything (as you do in factor 4).
Did you experiment with includeInLayout at all? It would be interesting to see how this property plays in your stats.
hi rick,
no, in an effort to keep the topic focused, i didn't do any flex framework-specific testing. feel free to post results if you do any.
colin
Very interesting ! Thk you for sharing those great infos.
I knew there was a reason why I used to insert a blank keyframe with a stop() action at the end of my tweens when they alpha'd to 0 ;-)
'Flash Player's display API offers three different tools for hiding display objects'
Actually 4. I use BlendMode.ERASE in Efflex.
another option - set the sprites x value to a value that is off the stage x=-100
Not sure about flash 10 but in earlier versions this gave faster rendering than visible =false;
Thanks Colin,
This is one of those topics most people think is a no-brainer, when in reality, it can and does affect performance and depth depending on how it's used. As always, thanks for your research.
Further to Tink's comment, I always use BlendMode.ERASE in place of alpha=0, as any MouseEvent can still be captured. Haven't benchmarked it myself, but have been assured it is faster than alpha. Would be interesting to see this method added to your tests.
Further to Tink's comment, I always use BlendMode.ERASE in place of alpha=0, as any MouseEvent can still be captured. Haven't benchmarked it myself, but have been assured it is faster than alpha. Would be interesting to see this method added to your tests.
Non-visible objects affect parent dimensions, so they also affect the hitTestPoint function and possibly the hitTestObject too. This is probably the same for masked objects.
I just spend several hours trying to fix a bug related to non-visible objects, when the best solution was to simply remove them...
Colin, thank you so much for this article.
Adobe, please fix this bug 741 or add some visibleWidth/visibleHeight properties for crying out loud.
Hey guys,
I had the interesting problem of dealing with (external/legacy) interactive invisible elements that were seriously affecting performance on my codebase with "alpha=0". I've found the following workaround to the problem for Flash 10 apps to keep interactivity working and performance high:
On Event.ENTER_FRAME set visible=true
On Event.EXIT_FRAME call stage.invalidate()
On Event.RENDER call visible=false
This will effectively save the performance cost associated with rendering the primitives, while keeping them active in the interactive event flow.