自定义的组件中加入多个MXML标记的子UI元素

来源:互联网 发布:mac 终端获取ip地址 编辑:程序博客网 时间:2024/05/20 18:01

http://www.munkiihouse.com/?p=37

这篇文章讨论了如何在一个定制的组件中加入多个UI元素

首先我们来看一下它定制的FORMITEM,单单看源代码,这个号称是FORMITEM的东西其实并没有从FORMITEM扩展,而是从HBOX扩展的,因此个人感觉是要装多少东西就装多少东西,看看作者在这故弄玄虚的背后到底要给我们讲解什么东西

 

 FLEX不支持将子元件在多层水平上加入到组件容器里去,例如你就不能使用HBOX创建一个元件,然后再在其内部放入其他的元件,并用在其他地方,如果你尝试这么做,那么你得到一个运行时错误,说“Multiple sets of visual children have been specified for this component”该组件申明了多个可视的组件集合

看来一切果然是不能想当然的,再来看看作者是如何解决这个问题的。

FLEX不支持这样的原因是编译器实在不知道对于这些额外的组件应该如何处理,应为各种各样的冲突和特殊情况都会出现。

然而有几种方法可以避免这样的情况

  1. 只将MXML组件声明为叶子类,(无继承类)
  2.  在ACTIONSCRIPT里面声明组件而不是在MXML里面
  3.  在类文件里显式的处理MXML组件的传递,并且将组件放在合适的地方

 方法3是最为灵活的,因此我们的作者也将以此为例子来为我们讲述如何使用这种方法来避免我们开头的情况

 

 

步骤一:在你的组件内部创建属性,这样MXML编译器就会将子组件付给这个组件,在例子中的如“children”属性,将传递给函数的值保存在一个全局变量中,以便在后面还可以获得使用,然后调用invalidateProperties() 函数,调用这个函数会引起FLEX在组件的后面某个阶段调用commitProperties() 函数,这样做很方便

 

步骤二:覆盖commitProperties() 函数,我们仅仅遍历那些传递给这个自定义组件的子组件,然后将他们正确的放入我们的容器中

 

步骤三:设置你在步骤一中创建的属性为此组件的默认属性,这意味着,我们在例子中定义的“children”属性会被自动的付给组件

 

 

 

 

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">    
    <!--
    * Set "children" to be the default property so we can easily set it from mxml
   
-->
    <mx:Metadata>
        [DefaultProperty("children")]
   
</mx:Metadata>           
    
    <mx:Script>
        <![CDATA[
   
            private var _children:Array = [];
            private var _childrenChanged:Boolean = false;                        
            
            /**
             * Set the &apos;content&apos; of this component, and then call invalidateProperties
             *
             * Note that if only one child is defined in mxml, then that child itself is passed in
             * If more than one child is defined, then an Array is passed in
             */

            public function set children( value:* ):void
            {
                if( value is DisplayObject )//这属于动态的类识别
                    _children = [ value ];
                else
                    _children = value;
               
                _childrenChanged = true;
                invalidateProperties();
            }
           
            public function get children():Array
            {
                return _children;
            }
           
           
            /**
             * During the commit properties phase is the best time to
             * add the children to their intended target
             */

            protected override function commitProperties():void
            {
                super.commitProperties();
               
                if( _childrenChanged )
                {
                    for each( var child:DisplayObject in _children )
                    {
                        b_content.addChild( child );
                    }
                }   
            }
                                              
            /**
             * These are just a few more properties to flesh out the example
             */

            []
            private var _label:String;
            public override function set label( value:String ):void
            {
                _label = value;
            }
            public override function get label():String
            {
                return _label;
            }
           
            []
            private var _labelWidth:Number;
            public function set labelWidth( value:Number ):void
            {
                _labelWidth = value;
            }
            public function get labelWidth():Number
            {
                return _labelWidth;
            }
           
        ]]>
    </mx:Script>   
    <mx:Label id="l_label" text="{_label}" width="{_labelWidth}" textAlign="right" />   
    <mx:Box id="b_content" direction="horizontal" horizontalGap="0" verticalAlign="middle" />   
</mx:HBox>

 

Things of note注意事项:

  • MXML编译器传递给你的'CHILDREN'的属性的值的类型将根据你声明的子组件的俄个数而变化,如果你只申明了一个子组件,那么此子组件将被传入此属性,如果多于一个子属性,那么值将被传递如数组
  •  在commitProperties()函数被调用的过程中将子组件放到合适的位置是很方便的,首先因为这个函数在FLEX获得一些处理器空余时间时将被调用,这意味着其性能很好,其次这个函数要等到所有的子组件被创建后才被调用,无需处理这两者被容器交叉调用的竞爭条件,最后这个函数调用后,依次调用measure(),updatedisplaylist()这确保你的组件外观正确无误,这样完成了正确的放置子组件
  •  [DefaultProperty]元数据标签必须嵌套在<mx:Metadata> 里面
  •  使用这个方法,你就可以为你的自定义组件创建数个属性,使用这个方法你就可以使用MXML为组件添加数个子组件