Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3351825
  • 博文数量: 530
  • 博客积分: 13360
  • 博客等级: 上将
  • 技术积分: 5473
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-13 13:32
文章分类

全部博文(530)

文章存档

2017年(1)

2015年(2)

2013年(24)

2012年(20)

2011年(97)

2010年(240)

2009年(117)

2008年(12)

2007年(8)

2006年(9)

分类: Web开发

2013-03-28 11:48:54

1.概述
      上篇文章《FLEX皮肤实例3_自定义类与皮肤交互数据》,相关资料《FLEX皮肤2_皮肤原理》。

      皮肤与组件的数据交互是双向中的
     1.皮肤调用组件属性:使用:
          [HostComponent("spark.components.Button")]
          例:{hostComponent.label}

     2.组件调用皮肤中的组件
          [SkinPart(required="true")]
          public var button:Button;
          这就是所谓的skin part

      Skin part也是skin contract的重要组成部分。

     
      Spark框架中许多组件已经内置了skin parts。
      比如,在官方《flex 4 API》中,Button组件只有一个名为labelDisplay的skin part(它继承自ButtonBase类)是TextBase类的实例,用来显示按钮标签。
      详见。

      比如:Panel类内置了3个skin part. contentGroup存储并布局所有子组件。controlBarGroup处理一个可选的控制条布局。titleDisplay用来显示用户传递过 来的面板title标题属性。这些skin part都是静态的;每个实例都只有一个。
      详见:

      通过Part不仅可以推送组件数据到皮肤中,组件也可以用它们来注册行为。定义了这些Part之后,由组件负责功能逻辑的实现,而皮肤则只负责所有可视化的内容及布局。如icon的外观表现通过Skin表示,而icon的事件监听则由组件负责。

  1. //组件
  2. [SkinPart(required="true")]
  3. public var icon:Image;
  4. //皮肤
  5. <mx:Image id="icon"/>
      SkinnableComponent还提供了partAdded和partRemoved方法,在增加或删除SkinPart时会调用这些方法。
      当part加载的时候,partAdded()会被调用,当part移除的时候partRemoved()方法会被调用。因此我们可以在这两个方法中添加相关事件处理逻辑。

2. skin part类型
skin part分为static、dynamic、deferred(延迟)。
  .static
      skin part随着皮肤实例化。它们在整个皮肤周期永远是可访问的,并且任何静态part实例只有一个。
      比如Button组件中的labelDisplay皮肤part就是静态的,所以你不能创建另一个名为labelDisplay的skin part,但你可以访问labelDisplay.

  .dynamic
      动态的skin parts是在需要时被实例化,许多组件不需要。
      这些通常是特定组件有关皮肤不可或缺的工作。
      例如,Spark ButtonBar组件有三个动态皮肤部件:firstButton, lastButton, 和middleButton。这些动态的skin parts负责处理按钮条上每个按钮的皮肤,但由于每个特定按钮可能有不同的样式,这取决于ButtonBar实例中需要应用动态实例化皮肤的条件。例如,一个只有两个按钮的ButtonBar并不需要middleButton因为它只会有左右按钮。

      动态的skin parts用于在运行时需要实例化子元素的那些组件。它们是mx.core.IFactory的实例,这个接口类被用来创建其它组件实例,因为该皮肤在应用程序运行时将创建这些所需新部件。

  .deferred
     延迟skin parts根据一些触发器的排序来实例化。当皮肤被创建和应用到组件上时这些部件可能不存在,直到用户或系统与该组件交互时它们才被添加。

Adobe官方给出的skin parts生命周期。


      程序运行中skin发生变化,就会调用detachSkin()方法,所有skin part相关的partRemoved()方法也会自动调用,开发人员可以在这两个方法里添加相应的事件监听。

  有些复杂的component 可能需要在skin创建后某个不确定的时间与skin part进行交互。Component需要知道partAdded()方法可能在skin初始化很久以后才会被调用。这样的skin part被称为延迟的(deferred part)。一个典型的例子就是TabNavigator, 当用户点击了某个Tab之后,component才会知道新的part然后调用partAdded()方法。

3. 数据传递时绑定hostComponent VS 皮肤parts
组件数据与皮肤的传递可通过二种方式,代码可参见Button
1.通过hostComponent,将组件属性与皮肤中的元素进行绑定
代码参见
ButtonSkin3.mxml:

点击(此处)折叠或打开

  1. <s:Skin xmlns:fx=""
  2. xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
  3.  
  4.     <fx:Metadata>
  5.        [HostComponent("spark.components.Button")]
  6.     </fx:Metadata>
  7.  
  8.     ...
  9.     
  10.     <!-- text -->
  11.     <s:Label text="{hostComponent.label}" color="0x131313"
  12.             textAlign="center"
  13.             verticalAlign="middle"
  14.             horizontalCenter="0" verticalCenter="1"
  15.             left="12" right="12" top="6" bottom="6"
  16.      />
  17. </s:Skin>

2.skin part
    在皮肤内定义一个id,并且在组件内定义一个skin part,按钮会识别这个skin part,从面将label属性推送到皮肤中。
代码参见
ButtonSkin4.mxml:

点击(此处)折叠或打开

  1. <!-- text -->
  2.     <s:Label id="labelDisplay" color="0x131313" textAlign="center"
  3.             verticalAlign="middle"
  4.             horizontalCenter="0" verticalCenter="1"
  5.             left="12" right="12" top="6" bottom="6"
  6.     />
ButtonBase.as

  1. [SkinPart(required="false")]
  2. public var labelDisplay:IDisplayText;
    Label不再绑定到hostComponent。相反,我给它一个id labelDisplay ,这是一个按钮组件所需的皮肤part。按钮组件自动处理数据,将它的label属性推送到labelDisplay。
    但是这里需要注意的事,我们不能直接直接给Button中的labelDisplay属性赋值。

4. Button按钮代码导读
1.spark.components.supportClasses.ButtonBase定义了SkinState元数据: up, over, down disabled。

2.spark.components.supportClass.ButtonBase类定义了SkinPart的成员变量labelDisplay,

  1. [SkinPart(required="false")]
  2. public var labelDisplay:TextBase;
      这就表示Button的皮肤中可以定义有文本对象,id为labelDisplay.
      required="false",表示这个part是可选的,如果为true,则表示皮肤中必须有一个TextBase对象。

3.对Button赋值
     现在对Button的label属性进行赋值,其执行过程如下:
(1) 调用set label函数
    public function set label(value:String):void
    {
        // ButtonBase中并没有label属性,而是将值传递给了content
        content = value;
    }

(2) 调用set content函数

点击(此处)折叠或打开

  1.     [Bindable("contentChange")]
  2.     public function get content():Object
  3.     {
  4.         return _content;
  5.     }
  6.     public function set content(value:Object):void
  7.     {
  8.         _content = value;
  9.         // 这里才将传递的label值传递给labelDisplay skin part
  10.         if (labelDisplay)
  11.             labelDisplay.text = label;
  12.         // 派发事件,通知与content绑定的对象,content的值被修改了
  13.         dispatchEvent(new Event("contentChange"));
  14.     }

      labelDisplay是静态的,在声明周期中只会存在唯一的实例。当加载静态SkinPart的皮肤时,SkinnableComponent基类负责将所有的静态part从skin加载到component中。加载完毕之后,component就可以直接使用这些实例了。
      SkinnableComponent还提供了partAdded和partRemoved方法,在增加或删除SkinPart时会调用这些方法。
      当part加载的时候,partAdded()会被调用,当part移除的时候partRemoved()方法会被调用。因此我们可以在这两个方法中添加相关事件处理逻辑。

点击(此处)折叠或打开

  1. override protected function partAdded(partName:String, instance:Object):void
  2.     {
  3.         super.partAdded(partName, instance);
  4.         
  5.         if (instance == labelDisplay)
  6.         {
  7.             labelDisplay.addEventListener("isTruncatedChanged",labelDisplay_isTruncatedChangedHandler);
  8.             
  9.             // 当添加文本框时,如果_content有值,则将这个值赋给文本框
  10.             if (_content !== undefined)
  11.                 labelDisplay.text = label;
  12.         }
  13.         else if (instance == iconDisplay)
  14.         {
  15.             iconDisplay.source = getStyle("icon");
  16.         }
  17.     }
  18.     
  19.     override protected function partRemoved(partName:String, instance:Object):void
  20.     {
  21.         super.partRemoved(partName, instance);
  22.         
  23.         if (instance == labelDisplay)
  24.         {
  25.             labelDisplay.removeEventListener("isTruncatedChanged",
  26.                                              labelDisplay_isTruncatedChangedHandler);
  27.         }
  28.     }

  29.     private function labelDisplay_isTruncatedChangedHandler(event:Event):void
  30.     {
  31.         if (_explicitToolTip)
  32.             return;
  33.         
  34.         var isTruncated:Boolean = labelDisplay.isTruncated;
  35.         
  36.         // 如果label被截断,则以tooltip方式显示整个label
  37.         super.toolTip = isTruncated ? labelDisplay.text : null;
  38.     }

参考文献
1.Flex4中的皮肤(4):使用SkinPart约束Skin . http://blog.csdn.net/thinkinside/article/details/4635138
2.FLEX4 在Spark皮肤中定义与使用新的皮肤机制.
3.Flex 4 皮肤功能介绍.
4.Flex4 Skinning 2: 皮肤协议. http://www.cnblogs.com/spoony/archive/2010/11/03/flex4-skinning-part02-skinning-contract.html
5.
6.
7.FLEX 4 SKINNING–皮肤中的动态元件.http://blog.lunastudio.cn/?p=218
8.Flex4 Skinning 4: 留言板示例.http://www.cnblogs.com/spoony/archive/2010/11/08/flex4-skinning-part04-notecard-demo.html
9.Flex4 Skinning 2: 皮肤协议.http://www.cnblogs.com/spoony/archive/2010/11/03/flex4-skinning-part02-skinning-contract.html

阅读(4639) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~