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的事件监听则由组件负责。
-
//组件
-
[SkinPart(required="true")]
-
public var icon:Image;
-
//皮肤
-
<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:
-
<s:Skin xmlns:fx=""
-
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
-
-
<fx:Metadata>
-
[HostComponent("spark.components.Button")]
-
</fx:Metadata>
-
-
...
-
-
<!-- text -->
-
<s:Label text="{hostComponent.label}" color="0x131313"
-
textAlign="center"
-
verticalAlign="middle"
-
horizontalCenter="0" verticalCenter="1"
-
left="12" right="12" top="6" bottom="6"
-
/>
-
</s:Skin>
2.skin part
在皮肤内定义一个id,并且在组件内定义一个skin part,按钮会识别这个skin part,从面将label属性推送到皮肤中。
代码参见
ButtonSkin4.mxml:
-
<!-- text -->
-
<s:Label id="labelDisplay" color="0x131313" textAlign="center"
-
verticalAlign="middle"
-
horizontalCenter="0" verticalCenter="1"
-
left="12" right="12" top="6" bottom="6"
-
/>
ButtonBase.as
-
[SkinPart(required="false")]
-
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,
-
[SkinPart(required="false")]
-
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函数
-
[Bindable("contentChange")]
-
public function get content():Object
-
{
-
return _content;
-
}
-
public function set content(value:Object):void
-
{
-
_content = value;
-
// 这里才将传递的label值传递给labelDisplay skin part
-
if (labelDisplay)
-
labelDisplay.text = label;
-
// 派发事件,通知与content绑定的对象,content的值被修改了
-
dispatchEvent(new Event("contentChange"));
-
}
labelDisplay是静态的,在声明周期中只会存在唯一的实例。当加载静态SkinPart的皮肤时,SkinnableComponent基类负责将所有的静态part从skin加载到component中。加载完毕之后,component就可以直接使用这些实例了。
SkinnableComponent还提供了partAdded和partRemoved方法,在增加或删除SkinPart时会调用这些方法。
当part加载的时候,partAdded()会被调用,当part移除的时候partRemoved()方法会被调用。因此我们可以在这两个方法中添加相关事件处理逻辑。
-
override protected function partAdded(partName:String, instance:Object):void
-
{
-
super.partAdded(partName, instance);
-
-
if (instance == labelDisplay)
-
{
-
labelDisplay.addEventListener("isTruncatedChanged",labelDisplay_isTruncatedChangedHandler);
-
-
// 当添加文本框时,如果_content有值,则将这个值赋给文本框
-
if (_content !== undefined)
-
labelDisplay.text = label;
-
}
-
else if (instance == iconDisplay)
-
{
-
iconDisplay.source = getStyle("icon");
-
}
-
}
-
-
override protected function partRemoved(partName:String, instance:Object):void
-
{
-
super.partRemoved(partName, instance);
-
-
if (instance == labelDisplay)
-
{
-
labelDisplay.removeEventListener("isTruncatedChanged",
-
labelDisplay_isTruncatedChangedHandler);
-
}
-
}
-
-
private function labelDisplay_isTruncatedChangedHandler(event:Event):void
-
{
-
if (_explicitToolTip)
-
return;
-
-
var isTruncated:Boolean = labelDisplay.isTruncated;
-
-
// 如果label被截断,则以tooltip方式显示整个label
-
super.toolTip = isTruncated ? labelDisplay.text : null;
-
}
参考文献
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) |