Study Flex《自定义ProgressBar组件》

一、描述

近来项目中要用到进度条,并且是竖直方向,此组件支持水平或竖直

二、解决方法

重写组件。主要思路:

1、创建进度背景条UI。

2、创建当前刻度条UI。

3、创建%比文字显示UI。

三、原因

已有组件不能满足需求要求

四、实现

1、新建ProcessBar.as,写组件生命周期的几个方法。

package components.processBar
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.text.TextLineMetrics;
	
	import mx.core.IFlexDisplayObject;
	import mx.core.IFlexModuleFactory;
	import mx.core.IFontContextComponent;
	import mx.core.IUITextField;
	import mx.core.UIComponent;
	import mx.core.UITextField;
	import mx.styles.ISimpleStyleClient;
	
	[Style(name="labelWidth", type="Number", format="Length", inherit="yes")]
	[Style(name="backgroundColor", type="uint", format="Color", inherit="no")]
	/**
	 * The height of the track in pixels. 
	 * Track height if direction is horizontal.
	 * Track width if direction is vertical.
	 * 
	 * @default NaN
	 */
	[Style(name="trackHeight", type="Number", format="Length", inherit="no")]
	[Style(name="barSkin", type="Class", inherit="no")]
	[Style(name="trackSkin", type="Class", inherit="no")]
	
	public class ProcessBar extends UIComponent implements IFontContextComponent
	{
		public function ProcessBar()
		{
			super();
		}
		
		private var _content:UIComponent;// 装载背景与进度条的容器
		private var _bar:IFlexDisplayObject;//进度条
		private var _track:IFlexDisplayObject;// 背景条
		private var _labelField:IUITextField;// 文字
		
		private var trackSkinChanged:Boolean = false;// 背景条
		private var barSkinChanged:Boolean = false;// 进度条
		
		/**
		 * 创建组件
		 */
		override protected function createChildren():void{
			super.createChildren();
			// 内容
			if (!_content){
				_content = new UIComponent();
				addChild(_content);
			}
			// 文字
			if (!_labelField){
				_labelField = IUITextField(createInFontContext(UITextField));
				_labelField.styleName = this;
				addChild(DisplayObject(_labelField));
			}
		}
		/**
		 * createChildren完成处理
		 */
		override protected function childrenCreated():void{
			super.childrenCreated();
			// Mark all of our skins as changed so they will get created.
			trackSkinChanged = true;
			barSkinChanged = true;
		}
		/**
		 * 样式更改
		 */
		override public function styleChanged(styleProp:String):void{
			var invalidate:Boolean = false;
			
			super.styleChanged(styleProp);
			
			if (styleProp == null || styleProp == "styleName"){
				// Wholesale change, need to update all skins
				barSkinChanged = trackSkinChanged  = true;
				invalidate = true;
			} else if (styleProp == "barSkin"){
				barSkinChanged = true;
				invalidate = true;
			} else if (styleProp == "trackSkin"){
				trackSkinChanged = true;
				invalidate = true;
			}
			
			if (invalidate){
				invalidateProperties();
				invalidateSize();
				invalidateDisplayList();
			}
		}
		/**
		 * 属性提交
		 */
		override protected function commitProperties():void{
			super.commitProperties();
			// labelField
			if (hasFontContextChanged() && _labelField != null){
				var index:int = getChildIndex(DisplayObject(_labelField));
				removeChild(DisplayObject(_labelField));
				_labelField = IUITextField(createInFontContext(UITextField));
				_labelField.styleName = this;
				addChildAt(DisplayObject(_labelField), index);
			}
			// trackSkin背景条
			if (trackSkinChanged){
				trackSkinChanged = false;
				createTrack();
			}
			// barSkin进度条
			if (barSkinChanged){
				barSkinChanged = false;
				createBar();
			}
			
			if(label == null){
				label = "%3%%";
			}
		}
		/**
		 * 度量(与高宽设置有关)
		 */
		override protected function measure():void{
			super.measure();
			
			var prefWidth:Number;
			var prefHeight:Number;
			
			var trackHeight:Number = getStyle("trackHeight");
			var preferredTrackWidth:Number = _track.measuredWidth;
			var preferredTrackHeight:Number = isNaN(trackHeight) ? _track.measuredHeight: trackHeight;

			var labelWidth:Number = getStyle("labelWidth");
			var lineMetrics:TextLineMetrics = measureText(predictLabelText());
			var textWidth:Number = isNaN(labelWidth) ? lineMetrics.width : labelWidth;
			var textHeight:Number = lineMetrics.height;
			
			if(direction == "horizontal"){
				prefWidth = Math.max(preferredTrackWidth,textWidth);
				prefHeight = preferredTrackHeight;
			}else if(direction == "vertical"){
				prefWidth = Math.max(preferredTrackHeight,textWidth);
				prefHeight = preferredTrackWidth;
			}
			
			measuredMinWidth = measuredWidth = prefWidth;
			measuredMinHeight = measuredHeight = prefHeight;
		}
		/**
		 * 更新列表
		 */
		override protected function updateDisplayList(unscaledWidth:Number,
													  unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			// 背景
			var bgColor:Object = getStyle("backgroundColor");
			if (bgColor === null || isNaN(Number(bgColor))){
				bgColor = 0xFFFFFF;
			}
			this.graphics.clear();
			this.graphics.beginFill(uint(bgColor),1);
			this.graphics.drawRect(0,0,unscaledWidth, unscaledHeight);
			this.graphics.endFill();
			
			var left:Number = 0;
			var top:Number = 0;
			// 文字计算
			var labelWidth:Number = getStyle("labelWidth");
			var lineMetrics:TextLineMetrics = measureText(predictLabelText());
			var textWidth:Number = isNaN(labelWidth) ? lineMetrics.width : labelWidth;
			var textHeight:Number = lineMetrics.height;
			// 进度条计算
			var trackHeight:Number = getStyle("trackHeight");
			trackHeight = isNaN(trackHeight) ? _track.measuredHeight : trackHeight;
			// 布局
			if(direction == "horizontal"){
				trackHeight = (trackHeight > unscaledHeight) ? unscaledHeight : trackHeight;
				
				_content.move(left,top);
				// 背景条
				_track.move(0, (unscaledHeight - trackHeight) / 2);
				_track.setActualSize(unscaledWidth, trackHeight);
				// 进度条
				_bar.move(0, (unscaledHeight - trackHeight) / 2);
				var w:Number = Math.max(0, _track.width * percentComplete / 100);
				_bar.setActualSize(w, _track.height);
			}else if(direction == "vertical"){
				//width
				trackHeight = (trackHeight > unscaledWidth) ? unscaledWidth : trackHeight;
				
				_content.move(left,top);
				// 背景条
				_track.move((unscaledWidth - trackHeight) / 2, 0);
				_track.setActualSize(trackHeight, unscaledHeight);
				// 进度条
				var h:Number = Math.max(0, _track.height * percentComplete / 100);
				_bar.move((unscaledWidth - trackHeight) / 2, _track.height - h);
				_bar.setActualSize(_track.width, h);
			}
			//文字
			var _labelLeft:Number = (textWidth > unscaledWidth) ? 0 : (unscaledWidth - textWidth);
			_labelField.move(left + _labelLeft / 2,top + unscaledHeight);
			_labelField.setActualSize(textWidth, textHeight);
			_labelField.text = getFullLabelText();
		}
		/**
		 * 创建背景条trackSkin
		 */
		private function createTrack():void{
			if (_track){
				_content.removeChild(DisplayObject(_track));
				_track = null;
			}
			// Create the track frame
			var trackClass:Class = getStyle('trackSkin');
			if (trackClass)
			{
				_track = new trackClass();
				if (_track is ISimpleStyleClient)
					ISimpleStyleClient(_track).styleName = this;
				_content.addChildAt(DisplayObject(_track), 0);//放在最底层
			}
		}
		/**
		 * 创建进度条barSkin
		 */
		private function createBar():void{
			if (_bar){
				_content.removeChild(DisplayObject(_bar));
				_bar = null;
			}
			// Create the bar
			var barClass:Class = getStyle('barSkin');
			if (barClass){
				_bar = new barClass();
				if (_bar is ISimpleStyleClient){
					ISimpleStyleClient(_bar).styleName = this;
				}
				_content.addChild(DisplayObject(_bar));
			}
		}
		
		//----------------------------------
		//  direction
		//----------------------------------
		
		private var _direction:String = "horizontal";
		[Inspectable(enumeration="horizontal,vertical", defaultValue="horizontal")]
		
		public function get direction():String{
			return _direction;
		}
		public function set direction(value:String):void{
			if (value == "horizontal" || value == "vertical"){
				_direction = value;
			}
			
			invalidateDisplayList();
		}
		
		private var _label:String;
		public function get label():String{
			return _label;
		}
		public function set label(value:String):void{
			_label = (value != null) ? value : resourceManager.getString("controls", "label");
			
			invalidateDisplayList();
		}
		
		//----------------------------------
		//  value
		//----------------------------------
		
		private var _value:Number = 0;
		public function get value():Number{
			return _value;
		}
		public function set value(_value:Number):void{
			this._value = _value;
		}
		
		private var _minimum:Number = 0;
		private var _maximum:Number = 100;
		
		/**
		 * 设置进度条值
		 */
		public function setProgress(value:Number, total:Number):void{
			_setProgress(value, total);
		}
		
		private function _setProgress(value:Number, maximum:Number):void{
			if (!isNaN(value) && !isNaN(maximum)){
				_value = value;
				_maximum = maximum;
				// 派发完成事件可以不要
				if (_value == _maximum && _value > 0){
					dispatchEvent(new Event(Event.COMPLETE));
				}
				
				invalidateDisplayList();
			}
		}
		/**
		 * 计算当前进度百分比
		 */
		public function get percentComplete():Number{
			if (_value < _minimum || _maximum < _minimum){
				return 0;
			}
			// Avoid divide by zero fault.
			if ((_maximum - _minimum) == 0){
				return 0;
			}
			// 百分比
			var perc:Number = 100 * (_value - _minimum) / (_maximum - _minimum);
			perc = (isNaN(perc) || perc < 0) ? 0 : perc;
			perc = (perc > 100) ? 100 : perc;
			
			return perc;
		}
		/**
		 * 获取当前进度的格式文字
		 */
		private function getFullLabelText():String{
			var current:Number = Math.max(_value /* - _minimum */,0);
			var total:Number = Math.max(_maximum /* - _minimum */,0);
			var labelText:String = label;
			
			if (labelText){
				labelText = labelText.replace("%1", String(Math.floor(current)));
				labelText = labelText.replace("%2", String(Math.floor(total)));
				labelText = labelText.replace("%3", String(Math.floor(percentComplete)));
				labelText = labelText.replace("%%", "%");
			}
			return labelText;
		}
		/**
		 * 计算文字
		 */
		private function predictLabelText():String{
			if(label == null){
				return "";
			}
			var labelText:String = label;
			var largestValue:Number = (_maximum != 0) ? _maximum : 100000;
			if(labelText){
				labelText = labelText.replace("%1", String(Math.floor(largestValue)));
				labelText = labelText.replace("%2", String(Math.floor(largestValue)));
				labelText = labelText.replace("%3", "100");
				labelText = labelText.replace("%%", "%");
			}
			
			var actualText:String = getFullLabelText();
			return ((labelText.length > actualText.length) ? labelText : actualText);
		}
		
		
		public function get fontContext():IFlexModuleFactory{
			return moduleFactory;
		}
		
		public function set fontContext(moduleFactory:IFlexModuleFactory):void{
			this.moduleFactory = moduleFactory;
		}
	}
}
2、新建进度条背景条ProcessBarSkin.mxml,此皮肤包括边框与填充色

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
			 xmlns:s="library://ns.adobe.com/flex/spark">
	<fx:Script>
		<![CDATA[
			override protected function initializationComplete():void
			{  
				useChromeColor = false;
				super.initializationComplete();
			}
			
			override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{  
				if(getStyle('barColor')) {  
					activeBar.color = getStyle('barColor');  
				}
				super.updateDisplayList(unscaledWidth, unscaledHeight);  
			}  
		]]>
	</fx:Script>
   <!-- layer 1: fill -->  
   <s:Rect left="1" right="1" top="1" bottom="1" >  
       <s:fill>
         <s:SolidColor id="activeBar" color="#5eb737" alpha="1"/>
      </s:fill>
    </s:Rect>
</s:SparkSkin>  
3、新建当前刻度条ProcessBarTrackSkin.mxml

<?xml version="1.0" encoding="utf-8"?>
<!--- The Spark skin class for the MX ProgressBar component's track. 

@see mx.controls.ProgressBar

@langversion 3.0
@playerversion Flash 10
@playerversion AIR 1.5
@productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
			 xmlns:s="library://ns.adobe.com/flex/spark" minHeight="10" >
	
	<fx:Script>
		/**
		 * @private
		 */
		override protected function initializationComplete():void
		{
			useChromeColor = false;
			super.initializationComplete();
		}
	</fx:Script>
	
	<!-- layer 1: border -->
	<s:Rect left="0" right="0" top="0" bottom="0" width="199">
		<s:stroke>
			<s:SolidColorStroke color="#5eb737" alpha="1" />
		</s:stroke>
	</s:Rect>
	
	<!-- layer 2: inner border -->
	<s:Rect left="1" right="1" top="1" bottom="1" >
		<s:fill>
			<s:SolidColor color="#5eb737" alpha="0.6" />
		</s:fill>
	</s:Rect>
</s:SparkSkin>
4、App应用

	<processBar:ProcessBar id="bar" x="200" y="50" width="50" height="100"
						   backgroundColor="0x000000" trackHeight="30"
						   barSkin="components.processBar.ProcessBarSkin"
						   trackSkin="components.processBar.ProcessBarTrackSkin"
						   direction="vertical" label="%3%%" value="30"
						   styleName="redBar"/>
更新刻度值调用:bar.setProgress(70,100);
五、说明
实践出真知

-------------------------------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值