Flex4之使用ActionScript构建组件
首先来说下ActionScript常用的三种方式
Flex的核心是MXML和ActionScript 。
MXML 是用于为 Flex应用程序进行用户界面组件布局, 它属于表示层,最终要编辑成ActionScript 并生成ActionScript 类文件在Flash Player上运行。如果你是个Java开发者就很好理解这一点,MXML 就好比是JSP/Struts/JSF,它们最终都会编辑成Java 类文件并在具备JAVA虚拟机环境的浏览器上运行。
所以说,Flex 最核心的还是ActionScript 。在Flex中,ActionScript是 类库的方式出现的,该类库包含组件 (容器和控件)、管理器类、数据服务类和所有其他功能的类
1. 内联方式
<mx:Button label="Say Hello" click="mx.controls.Alert.show('Hello,Flying')"/>
2. 级联方式
<mx:Button label="Say Hello" click="sayHello('Flying')"/> <mx:Script> <![CDATA[ import mx.controls.Alert; private function sayHello(param_name:String):void { Alert.show("Hello, "+param_name); } ]]> </mx:Script>
3. 外联方式
<mx:Script source="myFunction.as"/>
<mx:Button label="Say Hello" click="sayHello('Flying');"/>
// myFunction.asimport mx.controls.Alert; private function sayHello(param_name:String):void { mx.controls.Alert.show("Hello, "+param_name); }
上述方式为AS方法单独新建一个as文件,然后设置该方法为被调用文件的Script元素的source属性值,并可以在调用方法时传递参数,此文件可以在多个文件调用,从而实现了AS方法在多个文件中的重用。
其次呢就要说说今天重点的ActionScript构建组件了
可以使用ActionScript创建可重用的组件,并且在你的Flex程序中可以作为标签引用这个组件。在ActionScript中创建的组件能够包含图像元素,自定义业务逻辑,或者扩展已经存在的Flex组件。
在ActionScript中,Flex组件实现了类层次结构。每一个组件,都是Action类的实例。下图展示了这种层次结构的一部分。
所有Flex可视组件都是源自于UIComponent类。要创建自己的组件,你可以创建一个继承UIComponent的类,或者继承 UIComponent子类的类。
使用类作为自定义组件的超类,取决于你要实现的功能。例如,你或许需要一个自定义的按钮控件。你可以创建一个UIComponent类的子类,然后重写Flex Button 类的所有功能。更好更快创建自定义按钮组建的方法是创建一个Flex Button组件的子类,然后在自定义类中进行修改。
下面贴出代码【说明:一切都要从重用性来考虑,否则没有必要用构建组件】,仅供参考
PaddedPanel.as
- <SPAN style="FONT-SIZE: large">package components
- {
- import mx.containers.Panel;
- public class PaddedPanel extends Panel
- {
- public function PaddedPanel()
- {
- // Call the constructor of the superclass.
- super();
- // Give the panel a uniform 10-pixel
- // padding on all four sides.
- setStyle("paddingLeft", 10);
- setStyle("paddingRight", 10);
- setStyle("paddingTop", 10);
- setStyle("paddingBottom", 10);
- }
- }
- }</SPAN>
NumericDisplay.as
- <SPAN style="FONT-SIZE: large">package components
- {
- import flash.events.Event;
- import flash.events.MouseEvent;
- import mx.containers.Tile;
- import mx.containers.VBox;
- import mx.controls.Button;
- import mx.controls.TextInput;
- import mx.events.FlexEvent;
- public class NumericDisplay extends VBox
- {
- private var display:TextInput;
- private var buttonsTile:Tile;
- // Expose the _numButtons property to the
- // visual design view in Flex Builder 3.
- [Inspectable(defaultValue=10)]
- private var _numButtons:uint = 10;
- //原来主应用程序中的引用本类的组件属性是取决于改自定义组件类是否定了了set方法而已,当然属性名称与set方法名称一致
- private var _max:int=90;
- public function set max(v:int):void{
- }
- public function get max():int{
- return _max;
- }
- public function NumericDisplay()
- {
- addEventListener(FlexEvent.INITIALIZE, initializeHandler);
- }
- // numButtons is a public property that determines the
- // number of buttons that is displayed
- [Bindable(event="numButtonsChange")]
- public function get numButtons():uint
- {
- return _numButtons;
- }// //当numButtons被赋值时,发出numButtonsChanage事件,通知所有被绑定的getter方法执行一遍
- public function set numButtons(value:uint):void
- {
- _numButtons = value;
- dispatchEvent(new Event("numButtonsChange"));
- }
- // Gets called when the component has been initialized
- private function initializeHandler(event:FlexEvent):void
- {
- // Display the component
- paint();
- }
- // Add the label of the clicked button to the display
- private function buttonClickHandler(event:MouseEvent):void
- {
- display.text += (event.target as Button).label;
- }
- // Display the component
- private function paint():void
- {
- // Create the number display
- display = new TextInput();
- display.width=185;
- addChild(display);
- // Create a Tile container to
- // hold the buttons.
- buttonsTile = new Tile();
- addChild (buttonsTile);
- // Create the buttons and add them to
- // the Tile container.
- for (var i:uint = 0; i < _numButtons; i++)
- {
- var currentButton:Button = new Button();
- currentButton.label = i.toString();
- currentButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
- buttonsTile.addChild (currentButton);
- }
- }
- }
- }</SPAN>
CountryComboBox.as
- <SPAN style="FONT-SIZE: large">package components
- {
- import mx.controls.ComboBox;
- import flash.events.Event;
- public class CountryComboBox extends ComboBox
- {
- private var countryArrayShort:Array = ["US", "UK"];
- private var countryArrayLong:Array = ["United States", "United Kingdom"];
- // Determines display state. The inspectable metadata tag
- // is used by Flex Builder 3.
- [Inspectable(defaultValue=true)]
- private var _useShortNames:Boolean = true;
- // Implicit setter
- public function set useShortNames(state:Boolean):void
- {
- // Call method to set the dataProvider based on the name length.
- _useShortNames = state;
- if (state)
- {
- this.dataProvider = countryArrayShort;
- }
- else
- {
- this.dataProvider = countryArrayLong;
- }
- // Dispatch an event when the value changes
- // (used in data binding).
- dispatchEvent(new Event("changeUseShortNames"));
- }
- // Allow other components to bind to this property
- [Bindable(event="changeUseShortNames")]
- public function get useShortNames():Boolean
- {
- return _useShortNames;
- }
- }
- }</SPAN>
主应用程序mxml
<?xml version="1.0" encoding="utf-8"?>
- <SPAN style="FONT-SIZE: large"><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
- xmlns:s="library://ns.adobe.com/flex/spark"
- xmlns:mx="library://ns.adobe.com/flex/mx"
- minWidth="955"
- minHeight="600"
- xmlns:components="components.*">
- <s:layout>
- <s:BasicLayout/>
- </s:layout>
- <fx:Script>
- <![CDATA[
- import flash.events.Event;
- private function handleCloseEvent(eventObj:Event):void
- {
- status.text = "You selected: \r" + countries.selectedItem as String;
- }
- ]]>
- </fx:Script>
- <fx:Declarations>
- <!-- 将非可视元素(例如服务、值对象)放在此处 -->
- </fx:Declarations>
- <components:PaddedPanel
- title="Custom component inheritance"
- >
- <components:CountryComboBox
- id="countries"
- useShortNames="false"
- />
- <!--
- Use data binding to display the latest state
- of the property.
- -->
- <mx:Label text="useShortNames = {countries.useShortNames}"/>
- <mx:ControlBar horizontalAlign="right">
- <mx:Button
- label="Toggle Display"
- click="countries.useShortNames = !countries.useShortNames;"
- />
- <mx:Text id="status" text="Please select a country from the list above." width="136"/>
- <components:NumericDisplay numButtons="10" />
- </mx:ControlBar>
- </components:PaddedPanel>
- </s:Application>
- </SPAN>
当使用ActionScript组件的普遍目的是创建可配置和可重用的组件。例如,创建一个ActionScript组件,它带有属性,分发时间,定义了新的样式,具有自定义的皮肤,或其他的个性化的设置。
当创建一个自定的ActionScript组件时,一个设计上要考虑的事情是可重用性。也就是说,你希望创建一个紧紧的绑定带你的应用程序的组件,还是能够在多个应用中可重用的组件?
编写与特定应用程序紧耦合的组件,经常是组件依赖于应用程序的结构,变量名或其他细节。如果你改变了应用程序,你可能需要修改紧耦合的组件来反映这种变化。一个紧耦合的组件,在没有重写的情况下很难应用到其他应用程序中。
设计一个松耦合的组件用于重用。松耦合的组件需要有清晰可辨的接口来指定如何向组件传递信息,如何将将结果传回应用程序。
典型的松耦合组件是使用属性来向组件传递信息。这些属性通过默认存取器(setter和getter方法)来定义,指定参数的类型。在下边的例子中,CountryComboBox自定义组件定义了公共的userShortNames属性,此属性通过使用get userShortNames()和set useShortNames()存取器方法暴露_ userShortNames私有属性。
私有属性_userShortNames的Inspectable 元数据标签定义了一个特性,这个特性出现在Adobe? Flex? Builder?中的属性提示和标签内省器中。也可以使用这个元数据标签限制允许的属性值。
注意:所有公共属性出现在MXML的代码提示和属性检查器中。如果你有关于属性的额外的信息,这些信息能够帮助代码提示或属性检查器(像枚举型的值,或这个字符串实际是文件路径),那么也把额外的信息添加到[Inspectable]元数据中。
MXML代码提示和属性检查器来于相同的数据,所以,如果在一个中显示出来那么在另一个中也应该一直显示出来。
在另一方面,ActionScript代码提示,不需要元数据也可以正常工作,所以你在ActionScript中依据所在的上下文一直都可以看待适当的代码提示。Flex Builder使用public/protected/private/static等等修饰符加当前所在范围计算出ActionScript代码提示。
定义组件向主应用程序返回信息的最佳实践是设计组件分发事件,事件中包含要返回的数据。那样,主函数能够定义时间监听器来处理时间,并且采取适当的行动。也可以使用数据绑定在事件中。在下边的例子中,使用Bindable元数据标签是userShortName编程一个被绑定的属性。隐含的 userShortName属性的setter发送改变事件,这个过程使用了的Flex 框架的内部的机制,来使数据绑定正常工作。