当前位置: > > > Flex4 - 通过继承UIComponent来创建自定义组件

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>
评论0