Flex 4 beta版Spark组件的一个主要优势来自于一种完全不同地皮肤机制,它为开发人员提供了对应用程序视觉上更强的控制。本教程将告诉你如何对可视化组件构建皮肤。任何使用这些皮肤的组件都内置了这种机制。为了说明这一点,我将通过PowerWindow来说明,它是利用了这些skin parts皮肤部件以及skin states皮肤状态和其它皮肤功能的一个自定义面板,以使用户可以通过按钮重新调整大小,最小化和最大化组件。
要求
这篇文章需要用到以下软件和文件
    Flash Builder 4 beta     Download
    •        spark_skin_parts.zip (ZIP, 51 KB)

必备知识
     建议你要熟悉Flash Builder,MXML和 ActionScript的基础知识。
关于作者
    Drew Falkman是一位RIA开发人员,是Santa Monica, CA的培训师。
使用皮肤和skin parts
     Spark皮肤用于提高所应用组件的设计和布局。这些皮肤通常在MXML中创建,作为类被用于Flex中。在Flex 4之前,当你使用MX组件时(也称为Halo组件),只有一些简单地皮肤控制能力:你只能包装不同地图形或是在组件上基于API(Application Programming Interface)用编译后的SWF元素预定义一些皮肤样式。而新的Flex 4皮肤API实现一种重大的定制功能,包括:
•        定义自定义样式
•        用图像和预编译后的SWF元素
•        用Flash绘图API定义自定义图形元素
•        定义皮肤不同状态
•        添加涉及父级组件编程功能
•        添加skin parts或子组件
    Flex编程环境中新增的这些允许你利用皮肤大有作为。本质上讲皮肤可涉及到一个组件实例所有可视化方面的问题。在本教程中,我将涵盖最新处理方式:使用skin parts。
内置皮肤部件
      Spark框架中许多组件已经内置了skin parts。你可以访问Flex 4 API documentation查看已存在的skin parts。Spark对象的顶部显示了支持的皮肤,可以点击链接到达Skin Parts部分(见图1)。
图1 Button组件API文档的Skin Parts
    当你点击该链接时,你将在API页面SkinParts部分看到该组件中每个可用的skin parts的释义和对象继承链。注意在Button组件有一个名为labelDisplay的skin part(它继承自ButtonBase类)是TextBase类的实例(见图2),用来显示按钮标签。

图2 Spark Button类的Skin parts
Skin parts的类型
   如果你看清楚了Spark Button类skin part的定义,你将会看到类型申明是静态的。
    每个skin part可以是static静态, dynamic动态, 或deferred延迟,skin part的类型与在皮肤中如何实例化它有关系。另外,每个skin part可能是必须的也可能是可选的。若组件的skin part是必须的,那么只要创建一个皮肤其skin part都应要存在。
    静态的skin part随着皮肤实例化。它们在整个皮肤周期永远是可访问的,并且任何静态part实例只有一个。以Button为例,labelDisplay 皮肤部件是静态的,你不能创建另一个名为labelDisplay的skin part,但你可以访问labelDisplay编程部分(例如改变其text属性)。
   动态的skin parts是在需要时被实例化,许多组件不需要。这些通常是特定组件有关皮肤不可或缺的工作。例如,Spark ButtonBar组件有三个动态皮肤部件:firstButton, lastButton, 和middleButton。这些动态的skin parts负责处理按钮条上每个按钮的皮肤,但由于每个特定按钮可能有不同的样式,这取决于ButtonBar实例中需要应用动态实例化皮肤的条件。例如,一个只有两个按钮的ButtonBar并不需要middleButton因为它只会有左右按钮。
    动态的skin parts用于在运行时需要实例化子元素的那些组件。它们是mx.core.IFactory的实例,这个接口类被用来创建其它组件实例,因为该皮肤在应用程序运行时将创建这些所需新部件。
     延迟skin parts根据一些触发器的排序来实例化。当皮肤被创建和应用到组件上时这些部件可能不存在,直到用户或系统与该组件交互时它们才被添加。
声明和覆盖skin part
     现在准备好了PowerWindow组件就可以开始揉合一起与皮肤相关事宜。用Flex4,你可以创建一个新组件来处理特定功能,不需耦合设计。设计的事情由皮肤负责处理。
     PowerWindowSkin.mxml将负责控制组件布局,下载所提供的示例文件并通过选择File > Import Flex Project (FXP)导入到Flash Builder 4中。PowerWindowSkin.mxml文件在com.adobe.examples.sparkskinparts包中。
   注意:在Design view我通过右键点击PowerWindow组件并选择Create New Copy Of Skin来创建了该皮肤类文件。这个创建的新皮肤类概括了主题、组件和两者的连接。
    要明白Spark皮肤是如何工作的,我们需要从创建皮肤开始。首先,该组件将被应用于内置的Spark Panel组件中。通过使用元数据标签声明宿主组件来处理,如<>

  1. <?xml version= 1.0  encoding= utf-8 ?>
     
  2. <s:SparkSkin xmlns:fx= http://ns.adobe.com/mxml/2009  
     
  3.   xmlns:s= library://ns.adobe.com/flex/spark  
     
  4.   xmlns:mx= library://ns.adobe.com/flex/halo >
     
  5.        
     
  6.   <fx:Metadata>
     
  7.     [HostComponent( spark.components.Panel )]
     
  8.   </fx:Metadata>
     
  9.        
     
  10. </s:SparkSkin>
复制代码

这里MXML的根标签是SparkSkin,定义了该类是一个Spark皮肤类,(支持Spark主题)且通过继承链可以使用皮肤API。之后声明HostComponent元数据标签,你可以与宿主组件类中的成员进行交互,包括内置的skin parts,参照本地hostComponent属性。在组件中,你可以引用本地皮肤属性,这些特性可以使组件与皮肤间进行交互。
      Panel类内置了3个skin part(见图3). contentGroup存储并布局所有子组件。controlBarGroup处理一个可选的控制条布局。titleDisplay用来显示用户传递过来的面板title标题属性。请注意这些skin part都是静态的;每个实例都只有一个,在组件开始启动时创建它们,这些部件不是必须的,所以在你的皮肤中不必包括这些对象,但要小心某些组件要正常运行就必须要的skin parts。

图3 spark.components.Panel组件的skin parts
覆盖skin parts
     下一步是明白如何在你的皮肤中覆盖内置的部件。例如,你可能需要覆盖PowerWindow中标题的显示方式,由API文档声明有一个名为titleDisplay的skin part,且是TextBase的实例,然后你需要做的就是创建这个类的实例(或扩展自它的任何类)并设置其ID为titleDisplay,例如:

  1. <s:Label id="titleDisplay" horizontalCenter="0" textAlign="center" />
复制代码

这行代码将覆盖标题的默认布局,而将标题定位在面板的中心位置处。你也可以包装它在一个矩形里并添加一个渐变或是背景,也可以随你喜欢来控制标题显示方式,目标组件的标题将会自动地显示。如果你愿意,可以绑定一个对象的text属性为另一个值,例如:

  1. text="{hostComponent.labelProperty}"
复制代码

目前的情况是,这个皮肤不会显示目标面板的内容,因为它缺少另一个skin part——contentGroup。添加如下代码:

  1. <s:Group x="0" y="30" id="contentGroup" />
复制代码

这是一个简单地执行例子,你也可以做到,可能你需要添加更多对子对象布局的控制。这是过程:添加必须(和可选)的组件,设置它们的属性,按你喜欢的放置对象。请务必确保给予每个实例的ID能匹配API文档中定义的skin part。