Chinaunix首页 | 论坛 | 博客
  • 博客访问: 284731
  • 博文数量: 64
  • 博客积分: 3099
  • 博客等级: 中校
  • 技术积分: 615
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-29 19:38
文章分类

全部博文(64)

文章存档

2015年(1)

2014年(7)

2013年(6)

2012年(3)

2010年(11)

2009年(3)

2008年(19)

2007年(14)

我的朋友

分类: 系统运维

2010-09-29 15:38:49

创建可设计外观的组件

可设计外观的 Spark 组件在幕后并没有什么特殊举动。它们拥有数据属性并通过元数据宣传它们所需的外观部件和外观状态。它们还关联几个主要方法,用于管理外观和外观部件的生命周期。您可以轻松新建一个可设计外观的相同组件。

为了证明这一点,您可以创建一个简单的 NoteCard 组件,它可用于在屏幕上显示留言。在图 7 的示例中,应用程序创建了多张写有随机引言的留言。

图 7.NoteCard 组件实例。

主应用程序创建了一个包含随机引言的 NoteCard 并将它略作旋转。这个应用程序的有趣之处在于 NoteCard 类,它扩展了 spark.components.supportClasses.SkinnableComponent 类并将它关联到外观设计生命周期方法。

NoteCard.as:

package
{
 
[SkinState("normal")]
[SkinState("disabled")]
public class NoteCard extends SkinnableComponent
{
    public function NoteCard()
    {
        super();
    }
    
    [SkinPart(required="true")]
    public var labelElement:TextGraphicElement;
    
    [SkinPart(required="false")]
    public var closeButton:Button;
    
    private var _text:String;
 
    public function get text():String
    {
        return _text;
    }
 
    public function set text(value:String):void
    {
        if (_text == value)
           return;
        _text = value;
    }
 
    ...
}
}


这个组件声明了数据属性、外观状态和外观部件。在数据方面,NoteCard 有一个公共 text 属性。NoteCard 还有两个外观状态 normaldisabled,它们使用类顶部的 SkinStates 元数据进行声明。它告诉外观需要实施这两个状态。

NoteCard 还有两个通过 SkinPart 元数据声明的外观部件。SkinPart 元数据就在外观部件名称的上方。在本例中,labelElement 是必需的 TextGraphicElement 外观部件,而 closeButton 则是可选的 Button 外观部件。

由于外观是在运行时加载的,所以第一次启动组件时,无法确保您获得外观。也无法确保您获得所有外观部件,尤其当它们是可选部件时。框架负责将外观中声明的部件关联到组件属性定义,并通过外观设计生命周期方法通知组件它们已经准备就绪。

实施组件上的外观状态

要关联外观状态,您需要覆盖 getCurrentSkinState() 以返回外观现在应当处于的状态。在本例中,它将返回 "normal""disabled"。当某个事件导致外观状态失效时,组件应调用 invalidateSkinState()

NoteCard.as

package
{
[SkinState("normal")]
[SkinState("disabled")]
public class NoteCard extends SkinnableComponent
{
    ...
    override public function set enabled(value:Boolean) : void
    {
        if (enabled != value)
           invalidateSkinState();
        super.enabled = value;
    }
    
    override protected function getCurrentSkinState() : String
    {
        if (!enabled)
           return "disabled";
        return "normal"
    }
    
    ...
}
}


设置 enabled 属性后,setter 调用 invalidateSkinState()。此操作将通知外观需要更改其状态并调用 getCurrentSkinState()

将外观部件关联到组件

要关联外观部件,您应当覆盖两个主要方法:partAdded()partRemoved()。 这些方法将告诉您添加和删除特定外观部件的时间。加载外观时可以添加或删除部件;在运行时交换外观;某个部件上线,因为它被延迟并且可能只存在于某些状态 中,或是新建了一个动态部件。添加部件时,您应当把握机会,将所需的任何数据向下推入其中并关联起任何事件侦听函数。删除部件时,您应当执行相反操作。

NoteCard.as

package
{
public class NoteCard extends SkinnableComponent
{
    [SkinPart(required="true")]
    public var labelElement:TextGraphicElement;
    
    [SkinPart(required="false")]
    public var closeButton:Button;
    
    public function set text(value:String):void
    {
        if (_text == value)
           return;
        _text = value;
        
        if (labelElement)
           labelElement.text = value;
    }
 
    override protected function partAdded(partName:String, instance:Object) : void
    {
       super.partAdded(partName, instance);
       
       if (instance == labelElement)
           labelElement.text = _text;
       if (instance == closeButton)
           closeButton.addEventListener(MouseEvent.CLICK, closeButton_clickHandler);
    }
    
    override protected function partRemoved(partName:String, instance:Object) : void
    {
       super.partRemoved(partName, instance);
        
        if (instance == closeButton)
           closeButton.removeEventListener(MouseEvent.CLICK, closeButton_clickHandler);
    }
    
    protected function closeButton_clickHandler(event:MouseEvent) : void
    {
       event.stopPropagation();
       
       IVisualElementContainer(parent).removeElement(this);
    }
 }
}


partAdded() 中,当关联起 labelElement 时,我将 text 属性推入这个外观部件中。我还在 text setter 中检查 labelElement 是否存在并关联-如果是,我将确保 labelElement 的 text 属性与组件保持同步。在 partAdded() 中,我为 closeButton 外观部件添加一个单击事件侦听函数。在 partRemoved() 中,我确保删除了相同的单击事件侦听函数。

对于 SkinnableComponent, 这是您参与这种强大的外观设计机制所需的全部操作。当他人为这个组件创建外观时,他们需要实施外观状态并关联到外观部件,才能获得所需的行为。范例源文件 中可以找到图 6 中的黑板外观,虽然这是一个简单的组件定义,您却可以使用不同的外观彻底改变它的外观。这是外观设计的实力所在。

注意:创建可设计外观的组件时,您可能必须决定特定行为属于组件还是外观。没有清晰 且必须遵循的强硬路线。只要可以令您的工作变得更轻松就行。但是总体指导方针是,定义组件外观的所有项应放入使用 MXML 声明的外观文件中。另一方面,如果多个外观需要某个行为,将该行为放入可设计外观的组件中可能是个好主意。例如,滑块中缩览图的放置是在 VSlider 和 HSlider 中而不是在外观中完成的。

后续工作

Flex 4 beta 中的外观设计经历了一番重大修改。组件与其外观之间界限分明。组件包含组件的数据、行为及核心逻辑,而外观则定义组件的外观。组件使用 ActionScript 编写而成,外观则使用 MXML,如果没有 FXG 和新的状态语法,这一切不可能发生。组件与外观通过外观设计合同相互沟通。由于它们是彼此独立的文件,所以可以轻松换入新的外观,从而彻底改变组件的外 观。


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