Flex4 - 通过继承UIComponent来创建自定义组件
通过继承UIComponent来创建自定义组件,可以获得更好的性能。继承UIComponent的组件一般要覆盖重写createChildren(), measure(), commitProperties(), updateDisplayList(), styleChanged()等方法。
下面一个样例通过一个自定义一个图例标签组件来演示实现方法。

--- 使用 ---
下面一个样例通过一个自定义一个图例标签组件来演示实现方法。
效果图:



--- 自定义组件 IconLabel.as ---
package yu { import flash.display.DisplayObject; import mx.core.UIComponent; import spark.components.Label; /** * 前面一个图标,后面是label的组件 * ------------------------------------- * 失效方法 ---> 生效方法 * invalidateProperties() commitProperties() * invalidateSize() measure() * invalidateDisplayList() updateDisplayList() */ /** * 元数据标记指定自定义样式(图标与label的间距,并禁用样式继承) */ [Style(name="horizontalGap",type="int",inheriting="false")] public class IconLabel extends UIComponent { /** * 正确图标 */ [Embed(source="Success.png")] private var IconSuccess:Class; /** * 错误图标 */ [Embed(source="Error.png")] private var IconError:Class; /** * 当前图标 */ private var currentIcon:DisplayObject; /** * 文本标签 */ private var displayLabel:Label; /** * 文本标签显示的文字 */ private var _label:String; /** * 文本标签显示文字状态是否改变。(避免每次调用commitProperties()方法的时候吧所有的属性都重新赋值一边) */ private var labelChanged:Boolean = false; /** * 设置文本标签显示的文字,并调用对应的失效方法 */ public function set label(value:String):void{ this._label = value; this.labelChanged = true; //并不直接对displayLabel赋值,而是将所有的更新合并到一起,到下一帧生效,节约资源 invalidateProperties(); invalidateSize(); } /** * 成功状态 */ public static const STATUS_SUCCESS:String = "success"; /** * 失败状态 */ public static const STATUS_ERROR:String = "error"; /** * 当前状态 */ private var _status:String; /** * 状态是否改变。(避免每次调用commitProperties()方法的时候吧所有的属性都重新赋值一边) */ private var statusChanged:Boolean = false; /** * 设置状态. * 并增加了绑定,使这个组件属性可以绑定 */ [Bindable] public function set status(value:String):void{ this._status = value; this.statusChanged = true; invalidateProperties(); } /** * 获取状态. */ public function get status():String{ return this._status; } /** * 获取间距样式。如果未设置就返回5 */ private function get horizontalGapDefault():int{ var horizontalGap:Number = getStyle("horizontalGap"); return (horizontalGap == undefined) ? 5 : horizontalGap; } /** * 构造函数 */ public function IconLabel() { super(); } /** * 创建组建对象 */ override protected function createChildren():void{ super.createChildren(); //创建添加图标 if(this.currentIcon == null){ this.currentIcon = new IconSuccess(); } addChild(this.currentIcon); //创建添加文本标签 if(this.displayLabel == null){ this.displayLabel = new Label(); this.displayLabel.setStyle("verticalAlign","middle"); //this.displayLabel.setStyle("paddingBottom","-5"); } addChild(this.displayLabel); } /** * 更新组件属性 * invalidateProperties()失效方法被调用时此方法会调用 */ override protected function commitProperties():void{ super.commitProperties(); //更新标签 if(this.labelChanged){ //当值被提交时重置为false; this.labelChanged = false; this.displayLabel.text = this._label; } //更新图标 if(this.statusChanged){ this.statusChanged = false; removeChild(this.currentIcon); switch(this._status){ case STATUS_SUCCESS: this.currentIcon = new IconSuccess(); break; case STATUS_ERROR: this.currentIcon = new IconError(); break; } addChild(this.currentIcon); } } /** * 确定组件最佳尺寸和可选的最小尺寸 * invalidateSize()失效方法被调用时此方法会调用 */ override protected function measure():void{ super.measure(); //对于没有继承UIComponent的子对象:使用width和height获取大小 //对于继承UIComponent的子对象: //使用getExplicitOrMeasuredWidth()和getExplicitOrMeasuredHeight()获取大小 this.measuredHeight = this.measuredMinHeight = Math.max(this.currentIcon.height, this.displayLabel.getExplicitOrMeasuredHeight()); this.measuredWidth = this.measuredMinWidth = this.currentIcon.width + this.horizontalGapDefault + this.displayLabel.getExplicitOrMeasuredWidth(); } /** * 布局组件的内容,并执行任何所需的绘制和重绘 * invalidateSize()失效方法被调用时此方法会调用 */ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{ super.updateDisplayList(unscaledWidth,unscaledHeight); this.currentIcon.y = (unscaledHeight-this.currentIcon.height)/2; //对于继承UIComponent的子对象:使用Move()来定位,使用setActualSize()来决定尺寸 this.displayLabel.move( this.currentIcon.x + this.currentIcon.width + this.horizontalGapDefault, 0 ); this.displayLabel.setActualSize( unscaledWidth-this.currentIcon.width - this.horizontalGapDefault, unscaledHeight ); } /** * 样式改变执行任何所需的绘制和重绘 */ override public function styleChanged(styleProp:String):void{ super.styleChanged(styleProp); if(styleProp == "horizontalGap"){ invalidateSize(); invalidateDisplayList(); } } } }
--- 使用 ---
<?xml version="1.0" encoding="utf-8"?> <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" creationComplete="init()" xmlns:yu="yu.*" fontFamily="微软雅黑" fontSize="20"> <fx:Script> <![CDATA[ private function init():void{ var iconLabel:IconLabel = new IconLabel(); iconLabel.label = "失败啦"; iconLabel.status = IconLabel.STATUS_ERROR; iconLabel.setStyle("horizontalGap",15); this.addElement(iconLabel); } ]]> </fx:Script> <s:layout> <s:VerticalLayout paddingLeft="20" paddingTop="30"/> </s:layout> <yu:IconLabel label="成功啦" status="{IconLabel.STATUS_SUCCESS}" /> </s:Application>