views:

2422

answers:

4

What is the best way to determine if a component in Flex/Flash is showing on the user's screen? I'm looking for an analog to Java's Component.isShowing() method.

The show and hide events fire for visibility, and this seems to work for the first descendant of a ViewStack component, but not further down the display tree.

+2  A: 

UIComponent.visible is not necessarily valid for children of an object where visible=false. From the docs:

"In either case the children of the object will not emit a show or hide event unless the object has specifically written an implementation to do so."

I wrote a sample application that confirms this to be true. What you can do is walk up the display list checking for visible to be false on a parent. Basically "visible" gives false positives but shouldn't give false negatives. Here is a quick utility I put together:

package
{
 import flash.display.DisplayObject;

 import mx.core.Application;

 public class VisibilityUtils
 {
  public static function isDisplayObjectVisible(obj : DisplayObject) : Boolean {
   if (!obj.visible) return false;
   return checkDisplayObjectVisible(obj);
  }

  private static function checkDisplayObjectVisible(obj : DisplayObject) : Boolean {
   if (!obj.parent.visible) return false;
   if (obj.parent != null && !(obj.parent is Application))
    return checkDisplayObjectVisible(obj.parent);
   else
    return true;
  }
 }
}

I haven't done anything more than trivial tests on this but it should get you started.

cliff.meyers
+1  A: 

Strange as it seems, now that you mention it, I don't believe there is a simple test to determine whether a component is actually visible onscreen in the sense Component.isShowing() implies.

It's also true the show and hide events don't bubble by default, so if you want to be notified of visibility changes in a descendant of a ViewStack container, you'll need to listen for them explicitly. The implementation details would vary depending on what sort of behavior you were after, but to take the simple example:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:VBox>
     <mx:HBox>
      <mx:Button id="btn1" click="vs.selectedIndex = 0" label="Show 1" />
      <mx:Button id="btn2" click="vs.selectedIndex = 1" label="Show 2" />
     </mx:HBox>
     <mx:ViewStack id="vs" selectedIndex="0">
      <mx:Panel id="panel1">
       <mx:Label id="label1" text="Label 1" show="trace('showing label 1')" hide="trace('hiding label 1')" visible="{panel1.visible}" />
      </mx:Panel>
      <mx:Panel id="panel2">
       <mx:Label id="label2" text="Label 2" show="trace('showing label 2')" hide="trace('hiding label 2')" visible="{panel2.visible}" />
      </mx:Panel>
     </mx:ViewStack>
    </mx:VBox>
</mx:Application>

... you'll see the show and hide events for each label fire once their visible properties have been bound to their parent panels'. Hopefully that illustrates the point; you can extend it however best suits your application. Good luck!

Christian Nunciato
+4  A: 

You want to check if the component property visible is true and this is for all the parents of your component in the DisplayList, am I correct?

public static function isVisible(c : UIComponent) : Boolean {
    if (c == null) return false;
    if (c is Application) return c.visible;
    return c.visible && isVisible(c.parent);
}
kajyr
That looks like a good improvement to my code. Much simpler. Nice.
cliff.meyers
+1  A: 

... or avoiding recursion:

public static function isVisible(obj:DisplayObject):Boolean
{
    while (obj && obj.visible && obj !== Application.application)
    {
        obj = obj.parent;
    }
    return obj && obj.visible;
}
KspR