编写Flex 2组件
2008-10-11 22:51 宝宝合凤凰 阅读(433) 评论(0) 收藏 举报编写Flex 2组件
08月 11th, 2006 — Dreamer英文原文:《Writing Flex 2 Components》
原文地址:http://weblogs.macromedia.com/pent/archives/2006/07/writing_flex_2.cfm
译者:Dreamer。
编写Flex 2组件
我曾经对这个主题反复思考,并且对要把这篇文章写成怎样的复杂程度犹豫不决。事实是,在Flex 2中编写组件非常容易。我所做的决定就是从一个没有使用skin的组件或者后来再添加skin的组件来开始。
我认为skin非常简单(对我们这些非艺术家来说),所以我们将会“从零开始”创建一个组件和它的skin。
你可以点击这里看一个可以运行的示例。其中一些量表(Gauge)是有关联的,也就是说改变一个得值会影响到另外一个。那些标有“interactive”的会对鼠标响应。你可以去试一下。
首先,简单介绍一下组件。Flex中的UIComponent类是所有组件的基类。这个示例组件将会直接扩展自UIComponent——因此我使用了“从零开始”这个词。使用UIComponent将确保组件适合Flex framework并且同其他组件很好地相处。
成为Flex framework的一部分可以确保组件适当地被创建并且在正确的时间接收到事件。比如,当一个组件被创建时它的构造函数会被调用,但是这时并不会创建一些子元素(skins-量表(Gauge)的指针,外框,以及涂色)。当到了这些子元素被创建的时候,Flex framework会调用组件的createChildren()方法。但是这时候组件并不会显示出来,所以,Flex framework又将调用组件的updateDisplayList()方法。
我将会使用这些非常简单的量表(Gauge)组件作为例子。因为如何让Gauge工作以及这三个skin是已知的,所以说它非常简单。通常来说,组件就是这样的:为组件创建一个类然后加上皮肤显示这个组件。对于一个组件,你可以有多个组成该组件的类,而且确实有一些Flex组件是这样的。为了简短起见,我把这些都写到了一个class文件中。
你可以把一个组件想象成这样:一个为组件提供功能(定位Gauge的指针并响应事件)的核心类,一个为组件提供外观和风格的skin类。
这个Gauge组件有一个叫做gauge.Gauge(在gauge包中)的类和一个叫做gauge.skins.programmatic.GaugeSkin的默认skin类。在这个例子中也有可以选择的skin:gauge.skins.alternatives.SquareFrameSkin 和作为PNG文件的图形skin。
我不想对代码过多地探讨,你可以把它们下载下来然后看注释。我将会在这里讲解一下重点的地部分。
点击此处下载文件
(你需要Flex 2 SDK or Flex Builder 2来使用这些文件。不需要Flex Data Services。)
量表(Gauge)
这个Gauge非常简单:有一个表面或者说是外框,一个指针,以及一个指针外壳。这些都是外表。Gauge也有属性:最小值,最大值,以及可以影响指针的位置的值。当鼠标在Gauge的表面点击时它也会发送一个“gaugeClick”事件。
因为Gauge必须遵循Flex framework,所以必须编写一些函数:
createChildren()是用来创建skin的,因为他们都是这个组件的子组件。
measure()。当Flex framework想要获得组件的尺寸时,会调用这个函数。
updateDisplayList()。当显示组件的时候会调用这个函数。
除了函数外,Gauge所需要的style和event的定义也给出了。
Styles 和 Events
在定义一个类之前,你可以先定义这个类用到的styles。这个工作通过[Style]元数据标签来完成。这些定义告诉编译器,在类中使用某些name=value是可以的。
createChildren
Gauge可以创建它所需要的任何的子对象。比如,你可以添加一个Text组件来显示当前的值。当你写一个滑动条的时候,你会想到创建一个滑块,这个道理同样适用于这个有自己的外框指针的Gauge组件。创建这些外壳很简单,下面是关于如何创建外框:
当你为一个组件定义skin的时候,你要为skin定义一个类而不是一个实例。这点对于graphic skin以及programmatic skin都适用。这个Gauge通过一些变量来保存这些类的名字,而这些类由具有相同名字的style来初始化。
例如,创建外框skin:
var skin:Class = Class(getStyle(”frameSkin”));
var newSkin:IFlexDisplayObject = new skin();newSkin.name = “frameSkin”;
newSkin.styleName = this;
addChild(newSkin);
首先通过getStyle()来获得skin类。然后使用new关键字创建一个该skin的实例。这个newSkin被赋予一个名字(如果是programmatic skin,这个名字就是描述它做什么),并且它的style被设定成Gauge组件自身的style。这是很重要的一点。这些skin需要获得style信息而且Flex开发者很容易将style加到这个组件自身:
<Gauge backgroundColor=”blue” … />
Gauge并不在意它的背景色,但是外框的skin在乎。通过把skin的styleName设定为组件自身的style并且在skin的代码中调用getStyle()就可以从Gauge实例中获得style。
最后,这个skin作为一个child被添加到了Gauge里。
updateDisplayList
updateDisplayList是非常常见的一个函数。它是所谓的“总是发生”的函数。一个组件中的很多其他函数都是为在updateDisplayList()中使用的属性设定值或者创建其用到的东西。
对于Gauge来说,updateDisplayList()非常基础:
1.画出skin
2.旋转指针。
画出skin就是:定义它们的大小(拿外框来说,它的大小就是Gauge中的控件所覆盖区域的大小)并且把它们放到正确的位置(指针需要被放置到空间的中央,指针的外壳需要跟随指针移动)。
Gauge的指针需要旋转以便指向最大值和最小值之间的任意一个值。这也是在updateDisplayList()中要做的工作。
属性
Gauge类剩下的东西就是属性了,比如minimum,maximum,以及value。你可能会认为当你设定一个值得时候就要立刻相应地改变显示。其实并不是那样。
在组建的外观显示创建之前属性就已经被初始化了。例如,如果你有一个Gauge的值设成了30但是没有创建指针指向30,那样的话你显然不能改变显示。
通常来说属性会简单地设置一个内在的变量然后设置一个旗标(flag)。它们也会呼叫一个使显示无效的函数。比如,当Gauge的值改变的时候,你知道显示列表(display list)需要更新,所以呼叫了invalidateDisplayList()。这就为Flex framework设置了一个flag,以便在适当的时候调用updateDisplayList()方法。换句话来说,当一个对显示有影响的属性改变时,它就通会过调用invalidateDisplayList()来标记这个变化。如果一个属性影响了组件的大小,invalidateSize()就会被调用。然后Flex framework只需要呼叫一次更新函数。
按照习俗,属性是存储在以下划线开头的变量中的set和get方法。比如,maximum的set函数设定_maximum这个变量。这些都被称为“backing variables”。
Skins
你刚才已经了解skin是通过Gauge的createChildren()方法创建的。但是严密地说,什么才是“skin”?Skin是在形式上和其他组件很相似并且适合Flex framework的对象。一个skin作为一个子组件被添加到一个组件中。因为几个原因,Skin本身通常没有children:
•Skins被规定为“轻量级”,因为它们被频繁地调用。
•Skins通常扩展自mx.skins.ProgrammaticSkin 或 mx.skins.Border。这些类不是从UIComponent继承而来的所以也不支持children。
你并不一定要使用ProgrammaticSkin 或者Border作为你的skins的基类。如果你愿意你可以使用UIComponent。只需要记住一点:基类越复杂,render这个skin需要做的工作就越多。
Skin类型
有两种类型的skin:Programmatic和 Graphic。这个Gauge示例将展示如何使用这两种类型。
Programmatic skins完全是基于代码的。你使用ActionScript来制作图形。Flash Player中的画图API使得画线和外形(园,矩形,圆角矩形,等等)以及使用一致或者渐变的颜色为它们填充颜色变得很简单。
如果你看一下gauge.skins.programmatic.GaugeSkin类你将发现下面几点:
•public 类GaugeSkin 扩展自 Border。GaugeSkin从很适合作为背景图像的Border类扩展而来。
•switch( name )。updateDisplayList()方法中的switch( name )。许多Programmatic skin类实际上绘制了很多skin。比如,一个Button有很多skin:当它弹起的时候,当鼠标放在上面的时候,当被鼠标点击的时候,等等。你可以为每一种skin使用不同的类,但是因为skins非常相似,所以使用单独的一个类就可以了。在GaugeSkin中,指针,外框,以及指针的外壳在外观上都很简单,而且因为每个Gauge的外观之间没有什么不同,所以就把skins放到了单一的类中。
你还要注意GaugeSkin类是很简单的。当所有工作已经做好并且正确加载skins后就会调用updateDisplayList()。
举个例子,如果GaugeSkin绘制了frameSkin(name==”frameSkin”),那么backgroundColor, backgroundAlpha, borderColor, borderAlpha, 以及borderThickness都需要从组件获得的。那些没有被设值的style就被赋予缺省的值。
绘制Skin
使用Graphics对象来绘制skin。frameSkin通过下列语句绘制:
g.clear();
g.lineStyle( borderSize, borderColor, borderAlpha );
g.beginFill( bgColor, bgAlpha );
g.drawEllipse(x,y,w,h);
g.endFill();
首先,清除了graphic的表面,如果清除失败就会让你的skin看起来像是有人在上面乱画一样。接下来就设定了线条的style和填充颜色。注意它们都是通过style设定的。一个椭圆被绘制出来——他将有一个线条style的边框并且用所给的颜色填充。这个填充就结束了,因为你可以使用多个绘制命令同时填充。
Graphic Skins
一个graphic skin就是一个图像,格式可以是PNG(我的最爱),JPG,或者GIF。制作一个graphic skin非常简单:
1.打开你最喜欢的图像编辑器,比如Fireworks 8。
2.确定组件有多大。比如100*100像素。
3.在空间里画一些东西并保存图像。最好是使用PNG或者GIF格式,因为那样你可以有透明区域。
4.把这个graphic设定为skin。可以通过以下几个途径实现:
a)在标签右边:
<mx:GaugeSkin faceSkin=”@Embed(’myface.png’)” … />
b)作为style的一部分:
SampleStyle { faceSkin: Embed(”myface.png”) }
注意,为了使用graphic skin在Gauge类中中改变了多少代码?没有!!我们要的就是这样。你的组件的使用者应该可以通过样式表在Programmatic和Graphic skin之间进行切换。
我认为使用styles比编写代码简单的多。Styles可以很快地制作,查找以及更改。并且它对于开发来说也足够快,所以没有任何理由不去使用它们。
扩展Gauge
以上这些其实都是在创建组件:设定style和属性,计算值,绘制skin。Gauge,这个特别的组件比较有趣。但是假如你想要两个指针呢?你需要编写一个新的组件吗?
答案是不用,如果你已经编写了可以扩展的原始组件。
看一下这个DoubleGauge类:
•public 类 DoubleGauge 扩展自 Gauge。这个类扩展自Gauge,有Gauge的style和功能的所有优点。
•protected var secondNeedleSkin。这个对象保存了第二个指针的skin。这个类被设计成允许第二个指针有自己的skin,而不是重用Gauge类的needleSkin。
•var angle:Number = calculateAngleFromValue(_secondValue)。这个函数是在updateDisplayList()中定义的。它的功能就是可以让继承的类访问同一个角度计算。如果没有这个函数,就意味着这个计算会在Gauge的updateDisplayList()方法中实现——你必须把它重写一遍。
这就是如何创建两个指针的Gauge。如果需要,你可以创建有更多指针的Gauge。
总结
我希望你会发现在Flex 2种编写组件很容易。很显然这个例子组件并不是很复杂,但是它却是覆盖到了一个组件必需的所有东西:
•如何通过正确的函数来让组件适合Flex framework。
•如何定义style以及如何获得skin来使用styles。
•如何定义事件,分派事件,并处理事件。
•如何编写一个skin类——你所要做的所有工作就是让它漂亮点。
•如何使用一个graphic skin——注意使用它不需要改变任何代码。
•如何扩展一个skin并且使用它的protected函数——漂亮的代码重用。
祝你们编写组件顺利。快你们拿出的所有作品吧,我已经等不及要看了。
浙公网安备 33010602011771号