【问题标题】:Flex: Determine if a component is showingFlex:确定组件是否正在显示
【发布时间】:2010-10-01 22:16:02
【问题描述】:

确定 Flex/Flash 中的组件是否显示在用户屏幕上的最佳方法是什么?我正在寻找类似 Java 的 Component.isShowing() 方法。

showhide 事件触发可见性,这似乎适用于 ViewStack 组件的第一个后代,但不适用于显示树的下方。

【问题讨论】:

    标签: apache-flex flash events components


    【解决方案1】:

    这就是你真正需要的。 “Application.application”检查是徒劳的。

            /**
             * Returns `true` if this component is actually shown on screen currently. This could be false even with
             * "visible" set to `true`, because one or more parents could have "visible" set to `false`.
             */
            public static function isShowing (c : DisplayObject) : Boolean {
                while (c && c.visible && c.parent) {
                    c = c.parent;
                }
                return c.visible;
            }
    

    【讨论】:

      【解决方案2】:

      我试图以可重用的方式获得相同的结果.. 我几乎找到了一种使用 getObjectsUnderPoint() 的方法 - 这会返回一个特定点下的对象,z-ordered(即使它们不是兄弟姐妹,例如 ViewStack,弹出窗口等)。

      基本上,我在舞台的特定点下获取最顶层的显示对象,然后在显示对象层次结构中向上查找测试对象。如果我找到它,则该对象是可见的(层次结构中不可见的对象应该已经被 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;
      }
      

      【讨论】:

      • 如果左上角被另一个组件覆盖,它不会将组件检测为不可见吗?。
      • stage.getObjectsUnderPoint 应该返回一个包含所有在该位置具有“blitted”点的显示对象的数组,即使被其他显示对象覆盖(这就是返回数组而不是单个的原因对象)。
      【解决方案3】:

      ...或避免递归:

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

      【讨论】:

      • 如果您使用弹出窗口,Flex 在与应用程序不同的显示列表中创建它们,因此在父列表中测试 Application.application 将不起作用。应该使用 Stage,并且在所有情况下都可以使用。
      【解决方案4】:

      您想检查组件属性 visible 是否为 true,这是针对 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);
      }
      

      【讨论】:

      • 这看起来是对我的代码的一个很好的改进。简单得多。不错。
      • Implicit coercion of a value with static type flash.display:DisplayObjectContainer to a possibly unrelated type mx.core:UIComponent.。您应该将c 声明为DisplayObjectContainer
      【解决方案5】:

      看起来很奇怪,既然你提到了它,我不相信有一个简单的测试来确定组件在 Component.isShowing() 所暗示的意义上是否真的在屏幕上可见。

      默认情况下显示和隐藏事件也不会冒泡,因此如果您想在 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>
      

      ...一旦它们的可见属性绑定到它们的父面板',您将看到每个标签触发的显示和隐藏事件。希望这能说明这一点;您可以扩展它,但最适合您的应用程序。祝你好运!

      【讨论】:

        【解决方案6】:

        UIComponent.visible 不一定对 visible=false 的对象的子对象有效。来自文档:

        “在任何一种情况下,对象的子级都不会发出显示或隐藏事件,除非该对象专门编写了一个实现。”

        我编写了一个示例应用程序来确认这是真的。你可以做的是在显示列表中检查 parent 上的 visible 是否为假。基本上“可见”会给出误报,但不应给出误报。这是我整理的一个快速实用程序:

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

        我没有做任何比这方面琐碎的测试,但它应该让你开始。

        【讨论】:

        • 是否有任何理由停止在 Application 而不仅仅是当 parent==null 时?
        • 我似乎记得应用程序的“父”属性可能是指向同一实例的指针,这会导致无限循环。我不是 100% 确定,也不能轻易确认,因为我已经有几年没有从事任何 Flex 工作了。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-21
        • 1970-01-01
        • 2013-05-11
        • 1970-01-01
        • 2018-07-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多