`
ynshun
  • 浏览: 91362 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

如何创建FLEX自定义组件(1)

    博客分类:
  • Flex
 
阅读更多

我经常看到这个话题——编写组件。通过这个例子,我将告诉你如何从零开始编写一个组件。我将要写几篇文章来探讨这个主题,在最后你就可以创建自己的组件了。
我把自己选择的这个组件叫做循环选择按钮。这个组件的显示的是dataProvider 中的某条纪录和两个箭头组成的一个圆环。当你选择按钮的时候箭头就会旋转一点同时显示dataProvider 中的下一个值。你可以把它想象成一个没有下拉列表的ComboBox组件。

 

Flex框架
想要创建一个Flex组件你必须理解Flex框架。一个组件的创建需要几个阶段,而在这些阶段Flex框架将多次遍历组件的继承层次来决定布局。
举个例子,假设一个Application中有两个VBox。一个VBox中有一些Button控件而另一个中有一些Label控件。要创建这些组件,Flex框架需要首先创建Application,然后创建VBox,然后是VBox的子控件。这是一次遍历。
如果没有对任何一个VBox指定高度或者宽度,那么你可能希望VBox足够大以便能够包含所有的子控件,对吗?为了计算VBox的大小,Flex框架需要决定它的每个子控件的大小。由于Button和Label并没有明确指定大小,所以Flex框架还需要决定它们的大小。这是另一次遍历。
一旦所有的计算都完毕的时候,Flex框架需要获得组件的大小属性和它们的位置。这又是一次遍历。
如同你看到的那样,创建组件并不是一件简单的事情,但是一旦你掌握了其中的窍门,它也并不是那么地困难。
为了方便地创建组件,Flex框架调用各个组件中的特定方法。通过实现这些方法,可以简单地使你的组件很好地适应框架。
有两种创建组件的方法:扩展一个已经实现了你想要的大部分功能的既有组件,或者由所有类的父类也就是最基础的类“从零开始”创建组件。
扩展一个既有的组件是最经常用的方法,
而且他是你编写一个Flex程序的时候一直在使用的方法。当你使用一个根标签<mx:Application>创建主程序文件的时候,你就创建了一个组件(扩展自Application)。而当你创建了一个根标签为其它任意组件的MXML文件的时候,也相当于创建了一个组件;不论你是通过MXML还是ActionScript进行扩展组件的。


程序初稿
我们将会以修改HBox组件开始,但是从根本上来说我们想要扩展UIComponent。使用HBox可以很好地阐述概念。

让我们来看一下这个组件的设计,很显然有两部分:一个圆环按钮和一个标签(Label)。但是由于我们想要通过点击标签(Label)在各个选项之间循环,而Button当鼠标放上去或者进行点击的时候都会提供一些反馈,所以使用一个Button看起来更实用。但是一个Button看起来一点也不像上面的那个控件,所以可能使用LinkButton看起来会好一点。
使用HBox作为根标签创建一个新的MXML组件并将其命名为CycleSelectButtonV1.mxml(V1代表version 1)。向其中添加两个子控件:一个Image和一个LinkButton(将它的id设为”linkButton”)。将Image的大小设成20×20并将HBox的verticalAlign属性设为”middle”。如果你是使用FlexBuilder来创建这个组件的话,请将HBox预设的width和height去掉。
对Image标签做以下更改:
<mx:Image source="@Embed('../assets/cycle_component.gif')" 
    width="20" height="20" />
你可以像下面这样使用这个新组件:
<CycleSelectButtonV1 dataProvider="{choices}" 
    change="handleCycleChange(event)" />
这个HBox组件并没有dataProvider属性,也没有change事件。这些东西是需要你进行自定义。


事件和属性
这个组件将要分派一个change事件,所以你需要将这个告诉Flex编译器组件。将下面的代码添加到HBox根标签:
<mx:Metadata> 
    Event(name="change",type="flash.events.Event")] 
</mx:Metadata>
Event 元数据标签告诉Flex编译器在MXML标签中可以包含 change=”…”。用来作为事件的数据类型的类是缺省的,不过我想要明确写出来,这样就对哪个事件类会出现在事件处理函数中就没有疑问了。
要添加dataProvider这个属性,你需要编写一点ActionScript代码。将下面的Script块添加到Metadata标签下面:
<mx:Script> 
<![CDATA[ 
]]> 
</mx:Script>
<![CDATA 和 ]]>语法是为了告诉XML其中的任何东西都不需要做XML解析。在Script标签中添加CDATA块并不是必须的,但是加入你使用像 < 的符号,XML解析器会认为你正在写一个新的标签!
将下面的代码添加到 CDATA 块中:
import mx.collection.ArrayCollection; 
private var _dataProvider:ArrayCollection; 
public function set dataProvider( value:ArrayCollection ) : void 

    _dataProvider = value; 

public function get dataProvider() : ArrayCollection 

    return _dataProvider; 
}
这是编写一个属性的标准方式——使用set和get函数,并且变量值和函数名是一样的,只是前面加了一个下划线。有时候你可能会看到这种方式被称作后台变量(backing variable)。
这时候你可以测试一下组件了,而且可以将dataProvider和change添加到组件标签中;尽管它们不会起到任何作用。
当我思考这个组件的时候,我想到要像为ComboBox提供数据一样为这个组件提供数据。下面是一个示例:
[ {label:"Apples", value:1}, {label:"Oranges", value:2}, etc. ]
你可以添加所有你想要让标签(Label)显示的数据,接下来我将告诉你如何实现这个功能。


commitProperties
到现在为止,组件并不知道如何在LinkButton中显示数据。所以我们需要一些ActionScript代码。将下面的代码添加到Script块中:
override protected function commitProperties() : void 

    super.commitProperties(); 
    // we'll fill this in below 
}
部分Flex框架周期包括一个对commitProperties()函数的调用。在组件的所有属性都设定完毕之后就会调用这个函数,这一点很重要,因为你不知道在一个属性的set函数中是否调用了另外一个属性的set函数。例如,如果第三个属性的设定需要用到其它两个的值,那么设定第三个属性的唯一合理的地方就是在commitProperties()中。
我们将使用commitProperties()将LinkButton的label属性设定为dataProvider中的一个值。这个例子中它将会被设定为第一个条目。将下面的代码添加到super.commitProperties()下面:
linkButton.label = dataProvider[0].label;
这里可能会发生很多错误:dataProvider属性可能从来没有被设定或者它的第一个条目可能并没有label属性。不过现在我们假设所有的东西都设定好了。
再次运行这个程序你将会看到LinkButton的label变成了”Apples”。
如果在主程序文件中添加一些代码对CycleSelectButtonV1的dataProvider做一些更改,你觉得会发生什么事情?如果你更改了一个ComboBox 或者 DataGrid的dataProvider将会发生什么事情?ComboBox 或者 DataGrid将会显示新的值对不对?你肯定希望CycleSelectButton有同样的效果。
如果你这样写:cycleButton.dataProvider = newValue,这就是对dataProvider调用了组件的set函数:
public function set dataProvider( value:ArrayCollection ) : void 

    _dataProvider = value; 
}
重点提示:其中的_dataProvider发生了改变,但是LinkButton的label并没有改变。你可能会尝试将linkButton.label=value[0].label添加到这个set函数中,但是我希望你看到这样做有很多问题。首先,它“看上去”就不对。而且真正的问题是,当组件正在创建属性还未设定完毕的时候,LinkButton的label属性可能并不能被赋值。当然,在那之后它将可以被赋值,但是在属性设定阶段很多组件都不可能很容易地被改变。
可以被赋值的地方就是commitProperties()函数。调用commitProperties()函数最合理的地方就是set函数。尽管这“看上去”也不对,而且,它所做的事情不但和上面所做的是一样的,还具有相同的问题。
接下来我们就想要通知Flex框架commitProperties()函数需要被调用,而这只需要在set函数中调用invalidateProperties()函数就可以了。在Flex框架中invalidateProperties()函数的作用是设定一个标记(flag),这个函数的好处是你可以设定100个属性并调用invalidateProperties()函数100次,而commitProperties()只会被调用一次,非常有效率。对set函数作以下更改:
public function set dataProvider( value:ArrayCollection ) : void 

    _dataProvider = value; 
    invalidateProperties(); 
}


循环显示数据
上面的代码只是为了下一件事情做准备:将LinkButton的label显示dataProvider的下一条目。
第一个条目已经被直接写到了commitProperties()函数中,很显然这里我们需要一个变量来保存条目的索引。嗯,selectedIndex 这个变量听起来是个不错的选择,而且它和ComboBox以及很多其他的Flex控件也保持一致。为selectedIndex也建立一个set函数和一个get函数:
private var _selectedIndex:int = 0; 
public function set selectedIndex( value:int ) : void 

    _selectedIndex = value; 
    invalidateProperties(); 

public function get selectedIndex() : int 

    return _selectedIndex; 
}
你还需要更改commitProperties函数中的一行代码来使用selectedIndex:
linkButton.label = dataProvider[selectedIndex].label;
然后让LinkButton的click事件调用一个函数来在索引之间切换:
private function handleClick() : void 

    selectedIndex = selectedIndex + 1; 
    if( selectedIndex >= dataProvider.length ) selectedIndex = 0; 
    linkButton.label = dataProvider[selectedIndex].label; 
}
当然也要为LinkButton添加click事件:
<mx:LinkButton label="linkButton" click=handleClick()" />
现在运行程序并点击组件中的LinkButton,它应该循环显示dataProvider中所有条目的label。当点击LinkButton的时候就会调用handleClick()函数,这会使selectedIndex的值加1,所以当commitProperties被调用的时候就会显示与新的selectedIndex对应的dataProvider中条目。很酷吧?哈!


分派事件
最后,我们还要在selectedIndex发生改变的时候分派一个change事件。你可以在selectedIndex 的set函数中实现这个功能,但是这也意味着任何通过ActionScript对selectedIndex所做的更改都会分派这个事件,这不符合标准的Flex工作流程。所以,我们将在LinkButton的click事件处理函数中分派这个事件:
private function handleClick() : void 

    selectedIndex = selectedIndex + 1; 
    if( selectedIndex >= dataProvider.length ) selectedIndex = 0; 
    linkButton.label = dataProvider[selectedIndex].label; 
    dispatchEvent( new Event(Event.CHANGE) ); 
}
在主程序中你可以处理这个change事件并使用组件的selectedIndex来查看当前选中的是哪个条目。


总结
你可以使用任何Flex容器(例如HBox, VBox, Canvas)为基础来编写自己的组件,你只需要用MXML标签将向其中添加一些子组件,创建一个Script块并添加一些属性(使用set和get函数),然后覆写commitProperties()函数来应用这些属性。
在下一篇文章中我将会用ActionScript写一个相同的组件并且使其在每次被点击的时候旋转那个圆环图像。

分享到:
评论

相关推荐

    Flex 自定义组件ImageViewer

    在Flex中,自定义组件是开发者根据项目需求创建的特殊UI元素,可以扩展和定制标准的MX或Spark组件。本示例着重于一个名为“ImageViewer”的自定义组件,这通常是一个用于展示图像并可能包含缩放、平移等交互功能的...

    各种Flex自定义组件

    在标题“各种Flex自定义组件”中,我们可以推断这是一个包含多种定制Flex组件的资源集合。这些组件可能包括时间选择器、数据网格(datagrid)、树形视图(tree)和下拉组合框(combox)。每个组件都有其特定的用途和...

    flex自定义组件事件DEMO

    1. Flex自定义组件:Flex允许开发者通过继承现有的UIComponent或者更具体的类(如Button、Canvas等)来创建自定义组件。这样可以定义独特的外观、行为和功能。自定义组件通常包含以下几个关键部分: - 美观设计:...

    flex自定义组件介绍

    标题中的“flex自定义组件介绍”指的是在Adobe Flex框架中创建和使用自定义组件的过程。Flex是一个基于ActionScript和MXML的开源框架,用于构建富互联网应用程序(RIA)。自定义组件允许开发者根据特定需求扩展Flex...

    flex 自定义组件

    Flex自定义组件是Adobe Flex框架中的一个重要特性,它允许开发者创建具有特定功能和外观的UI元素,以满足项目中独特的用户界面需求。Flex是一个开源的、基于MXML和ActionScript的开发框架,主要用于构建富互联网应用...

    flex 高级自定义组件

    在Flex中,可以通过继承UIComponent类来创建自定义组件。UIComponent是所有可视化组件的基础,提供了许多用于组件管理的属性和方法。为了改变组件的外观特征,开发者常常需要重写`commitProperties()`方法。这个方法...

    Flex自定义组件和事件

    ### 一、Flex自定义组件 #### 1. 创建自定义组件的原因 在Flex应用中,有时标准组件库提供的组件无法满足特定的设计或功能需求。此时,开发者需要创建自定义组件来扩展Flex的功能,以实现个性化设计或定制化行为。...

    Flex4自定义组件开发.pdf

    在Flex4中,自定义组件的开发变得尤为重要,因为它允许开发者创建高度定制化的UI组件,以满足特定的应用需求。 #### 二、Spark组件架构剖析 Flex4采用了全新的Spark组件架构,与之前的Flex3(Halo组件架构)相比有...

    Flex 分页组件,flex自定义组件

    在Flex中,分页组件通常是自定义组件,因为Flex的标准库并未提供内置的分页解决方案。开发者通常需要根据实际需求来设计和实现这样的组件。以下是对Flex分页组件的详细解释: 1. **分页机制**:分页的核心是将大...

    谈谈flex自定义组件

    Flex组件开发可分为两种. 一是在mxml中创建自定义组件.另一种则在actionscript class中创建,分别知道他们的含义。

    flex4自定义组件皮肤

    在Flex4中,自定义组件皮肤是提升应用视觉效果和用户体验的重要手段。下面将详细介绍如何在Flex4中自定义组件皮肤。 1. **组件皮肤的基本概念** - 组件皮肤是Flex中改变组件外观的一种方式,通过定义不同的皮肤,...

    Flex各自定义组件事件通讯例子

    Flex自定义组件是指开发者根据项目需求,通过继承已有的Flex基类(如UIComponent或Canvas),并添加特定功能和样式来创建的组件。自定义组件可以扩展Flex库中默认组件的功能,提高代码重用性和灵活性。 1. 组件创建...

    第五章 自定义组件开发 第一节 自定义Flex组件

    在自定义组件时,开发者可以继承Flex提供的基类,如UIComponent或Canvas,然后添加自己的属性、方法和样式。 创建自定义Flex组件的步骤通常包括以下几点: 1. **定义组件类**:首先,你需要创建一个新的AS3类,并...

    Flex4 自定义组件皮肤小结

    以压缩包中的`pureMVC_Simple`为例,PureMVC是一个轻量级的框架,它并不直接涉及Flex4的皮肤机制,但我们可以将其与Flex4的自定义组件皮肤结合起来,创建一个具有PureMVC风格的用户界面。例如,我们可以通过自定义...

    flex 自定义控件、事件

    深入学习Flex自定义控件和事件处理,不仅可以帮助你创建高度定制的应用,还能提高代码复用性和可维护性。通过实践和研究,开发者可以更好地掌握Flex的精髓,从而构建出更具吸引力和交互性的用户界面。

    Flex3自定义组件类似于Fieldset

    Flex3自定义组件类似于Fieldset

    flex自定义组件

    在本文中,我们将深入探讨`Flex`布局以及如何在前端开发中创建自定义组件,特别是针对`Flex`下的下拉组件。`Flex`布局是一种强大的CSS(层叠样式表)布局模式,允许开发者轻松地创建响应式和动态的用户界面。这种...

    flex/flash自定义组件(搜索栏)

    本文主要探讨如何在Flex中自定义组件,特别是针对一个搜索栏的实现。在提供的压缩包中,我们有`searchField.fla`、`searchField.swf`以及`documentClasses`这三个文件,它们分别代表了不同阶段的开发过程。 1. **...

    flex自定义文本编辑器

    在Flex开发中,创建自定义组件是提升应用用户体验和功能扩展性的重要手段。"flex自定义文本编辑器"是一个这样的示例,它展示了如何利用Flex4框架构建一个具备特定功能的文本编辑工具,同时集成了自定义的拾色器功能...

    flex图片放大镜组件,自定义组件

    在IT行业中,自定义组件是前端开发中的一个重要概念,它允许开发者根据特定需求创建功能独特、界面个性化的UI元素。本案例中提到的"flex图片放大镜组件"就是这样一个自定义组件,它专为图片展示站点设计,提供了一个...

Global site tag (gtag.js) - Google Analytics