Flex. Определите, отображается ли компонент.

Каков наилучший способ определить, отображается ли компонент в Flex/Flash на экране пользователя? Я ищу аналог Java метод Component.isShowing().

События show и hide срабатывают для видимости, и это, похоже, работает для первого потомка компонента ViewStack, но не дальше по дереву отображения.

Ответ 1

UIComponent.visible необязательно действителен для дочерних объектов объекта, где visible = false. Из документов:

"В любом случае дети объекта не будут вызывать событие show или hide, если объект специально не написал реализацию для этого."

Я написал пример приложения, подтверждающий, что это правда. То, что вы можете сделать, - это подождать, пока список отображения будет отображаться как ложный для родителя. В принципе "видимый" дает ложные срабатывания, но не должен давать ложных негативов. Вот краткая утилита, которую я собрал:

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

Я не делал ничего более, чем тривиальные тесты, но вам нужно начать.

Ответ 2

... или избежать рекурсии:

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

Ответ 3

Вы хотите проверить, является ли свойство компонента видимым, и это относится ко всем родителям вашего компонента в DisplayList, правильно ли?

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

Ответ 4

Как ни странно, теперь, когда вы упомянули об этом, я не верю, что есть простой тест, чтобы определить, действительно ли компонент отображается на экране в смысле Component.isShowing().

Также верно, что события show и hide по умолчанию не пузырятся, поэтому, если вы хотите получать уведомления о изменениях видимости в потомке контейнера ViewStack, вам нужно будет их явно прослушать. Детали реализации будут различаться в зависимости от того, какое поведение вы выполняли, но для простого примера:

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

... вы увидите шоу и скройте события для каждого ярлыка, как только их видимые свойства будут привязаны к их родительским панелям. Надеюсь, это иллюстрирует суть; вы можете расширить его, но лучше всего подходит для вашего приложения. Удачи!

Ответ 5

Я пытался получить то же самое в многоразовой манере. Я почти узнал способ использования getObjectsUnderPoint() - это возвращает объект под особой точкой z-упорядочен (даже если они не являются братьями и сестрами, например ViewStack, Popups, ecc.).

В принципе, я получаю самый верхний экранный объект под определенной точкой сцены, а затем идем вверх по иерархии экранных объектов, чтобы найти тестируемый объект. Если я найду его, объект будет виден (невидимые объекты в иерархии должны быть уже отфильтрованы вызовом getObjectsUnderPoint).

Проблема заключается в том, что вы должны использовать непрозрачную точку своего объекта (в моем случае я использовал смещение 5 пикселей из-за граничных границ), иначе он не будет подхвачен этой функцией.

Любые идеи по его улучшению?

Косма

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