来自:http://www.5uflash.com/Html/flex/223818539.html
文原文:Component Class
原文地址:http://weblogs.macromedia.com/pent/archives/2007/10/component_class.cfm
原文作者:Peter Ent
组件类
我经常看到这个话题——编写组件。通过这个例子,我将告诉你如何从零开始编写一个组件。我将要写几篇文章来探讨这个主题,在最后你就可以创建自己的组件了。
我把自己选择的这个组件叫做循环选择按钮。这个组件的显示的是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()函数来应用这些属性。
分享到:
相关推荐
Flex视图切换,自定义控件Demo.rar Flex视图切换,自定义控件Demo.rar Flex视图切换,自定义控件Demo.rar Flex视图切换,自定义控件Demo.rar
Flex 组件Flex 组件Flex 组件Flex 组件Flex 组件
研究Flex 组件声明周期,了解组件的生成步骤
Flex4自定义组件 介绍了flex中如何自定义组件以及相关应用
很通用的Flex 分页组件,经过本人测试,可以应用到项目中,很方便
flex 自定义组件,UI,flex 自定义组件。
flex 高级自定义组件 需要重写的方法,以及为什么要重写,何时调用等。
Flex自定义组件和自定义事件的使用。 Flex自定义组件和自定义事件的使用。
flex开发自定义控件
一些flex组件的用法! flex组件用法。 自定义控件
学习flex,学习开发自定义控件。顶起RIA应用程序!www的下一代技术!
FLex自定义写的控件,有时间,datagrid,tree,combox等,以及常用的处理字符串,弹出窗口
Flex 自定义 时间 日历 控件
flex4.5自定义组件介绍,自定义组件前提条件
Flex中如何创建自定义排序DataGrid控件的例子
详解Flex4.0自定义控件的开发步骤以及注意事项
你还在头痛flex4组件皮肤怎么自定义吗?看我给你们上传的吧;因皮肤中还是有部分mx组件,如果不能正常使用,请自己把所以mx组件改成sp组件
NULL 博文链接:https://whp0731.iteye.com/blog/726223
flex自定义组件事件DEMO,一个简单的flex自定义组件的demo
Flex4开发的自定义输入框皮肤组件,代图标,圆角,主要测试Flex4 spark主题下如何自定义组件皮肤。