2009-01-16 9 views
11

Was ist der beste Weg festzustellen, ob eine Komponente in Flex/Flash auf dem Bildschirm des Benutzers angezeigt wird? Ich suche nach einem Analog zu Javas Component.isShowing() Methode.Flex: Ermitteln, ob eine Komponente angezeigt wird

Die Ereignisse show und hide werden für Sichtbarkeit ausgelöst, und dies scheint für den ersten Nachkommen einer ViewStack-Komponente zu funktionieren, aber nicht weiter unten in der Anzeigebaumstruktur.

Antwort

5

UIComponent.visible ist nicht unbedingt für untergeordnete Objekte eines Objekts gültig, für die visible = false gilt. Aus der Dokumentation:

"In beiden Fällen werden die untergeordneten Elemente des Objekts kein Show- oder Hide-Ereignis ausgeben, es sei denn, das Objekt hat eigens dafür eine Implementierung geschrieben."

Ich schrieb eine Beispielanwendung, die dies bestätigt. Sie können die Anzeigeliste aufsuchen, um zu prüfen, ob auf einem Elternelement ein Fehler angezeigt wird. Grundsätzlich bedeutet "sichtbar" falsch-positive Ergebnisse, sollte aber keine falsch-negativen Ergebnisse liefern. Hier ist eine kurze Dienstprogramm, das ich zusammen:

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; 
     } 
    } 
} 

Ich habe nichts mehr als trivial Tests auf das getan, aber es sollte Ihnen den Einstieg.

+0

Gibt es einen Grund bei Anwendung zu stoppen und nicht nur dann, wenn Eltern == null? –

+1

Ich erinnere mich, dass die "Eltern" -Eigenschaft der Anwendung möglicherweise ein Zeiger auf dieselbe Instanz ist, die eine Endlosschleife verursachen würde. Ich bin mir nicht 100% sicher und kann das nicht leicht bestätigen, da ich seit ein paar Jahren keine Flex-Arbeit mehr mache. –

1

Seltsam wie es scheint, jetzt, wo du es erwähnst, glaube ich nicht, dass es einen einfachen Test gibt, um zu bestimmen, ob eine Komponente tatsächlich auf dem Bildschirm im Sinne von Component.isShowing() sichtbar ist.

Es stimmt auch, dass die Ereignisse zum Ein- und Ausblenden standardmäßig nicht aktiviert sind. Wenn Sie also über Änderungen der Sichtbarkeit eines Nachfahrens eines ViewStack-Containers informiert werden möchten, müssen Sie explizit darauf achten. Die Details der Implementierung variieren würden je nachdem, welche Art von Verhalten waren Sie nach, aber das einfache Beispiel zu nehmen:

<?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> 

... Sie werden die Show sehen und Ereignisse für jedes Etikett Feuer verstecken, sobald ihre sichtbaren Eigenschaften haben an ihre übergeordneten Gremien gebunden ". Hoffentlich veranschaulicht das den Punkt; Sie können es erweitern, aber es passt am besten zu Ihrer Anwendung. Viel Glück!

7

Sie möchten überprüfen, ob die Komponente Eigenschaft sichtbar ist und dies gilt für alle Eltern Ihrer Komponente in der DisplayList, bin ich richtig?

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); 
} 
+0

Das sieht wie eine gute Verbesserung für meinen Code aus. Viel einfacher. Nett. –

+0

'Implizite Koerzition eines Wertes mit dem statischen Typ flash.display: DisplayObjectContainer auf einen möglicherweise nicht verwandten Typ mx.core: UIComponent.'. Sie sollten 'c' als' DisplayObjectContainer' deklarieren. –

11

... oder Vermeidung von Rekursion:

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

Wenn Sie Popups verwenden, erstellt Flex diese in einer anderen Anzeigeliste als die Anwendung. Daher funktioniert das Testen der Application.application in der übergeordneten Liste nicht. Bühne sollte stattdessen verwendet werden und wird in allen Fällen funktionieren. – Chris

0

Ich habe versucht, das gleiche in einer wieder verwendbaren Weise zu erhalten .. ich fast eine Art und Weise unter Verwendung von getObjectsUnderPoint fand heraus() - dies gibt das Objekt unter ein particolar Punkt, z-geordnet (auch wenn sie nicht Geschwister sind, zB ViewStack, Popups, etc.).

Grundsätzlich bekomme ich das oberste Anzeigeobjekt unter einem bestimmten Punkt der Bühne und gehe dann nach oben zur Anzeigeobjekthierarchie, um das getestete Objekt zu finden. Wenn ich es finde, ist das Objekt sichtbar (nicht sichtbare Objekte in der Hierarchie sollten bereits durch den Aufruf getObjectsUnderPoint herausgefiltert werden).

Das Problem hier ist, dass Sie einen nicht transparenten Punkt Ihres Objekts verwenden müssen (in meinem Fall habe ich einen Offset von 5 Pixel wegen der runder Grenzen verwendet), sonst wird es von dieser Funktion nicht aufgenommen.

Irgendwelche Ideen, um es zu verbessern?

Cosma

public static function isVisible(object:DisplayObject):Boolean { 
    var point:Point = object.localToGlobal(new Point(5, 5)); 
    var objects:Array = object.stage.getObjectsUnderPoint(point); 
    if (objects.length > 0) { 
     if (isDescendantOf(object, objects[objects.length - 1] as DisplayObject)) { 
      return true; 
     } 
    } 
    return false; 
} 

public static function isDescendantOf(parent:DisplayObject, child:DisplayObject):Boolean { 
    while (child.parent != null) { 
     if (child.parent === parent) { 
      return true; 
     } else { 
      child = child.parent; 
     } 
    } 
    return false; 
} 
+0

Wird eine Komponente nicht als unsichtbar erkannt, wenn die obere linke Ecke von einer anderen Komponente abgedeckt wird? –

+1

stage.getObjectsUnderPoint sollte ein Array aller Anzeigeobjekte zurückgeben, die an dieser Position einen Punkt "blind" haben, selbst wenn es von anderen Anzeigeobjekten bedeckt ist (daher wird ein Array anstelle eines einzelnen Objekts zurückgegeben). –