Flex 的默认的 Preloader, 平心而论,不是很好看。一个个性化的Preloader,基本上要包括三个部分
1. 公司或者网站Logo,或者个性化的预载图片。好似是桌面软件的Splash Screen。
2. 载入数据的进度,文字形式的百分比。
3. 载入进度条
preloader不像Flex项目中普通的部件可以通过CSS进行设置,是因为当程序初始载入时,CSS文件的设定还未被载入,所以不好通过CSS进行外观的控制
这里有Ted把SWF,GIF 和 PNG 文件作为 Preloader 的教程。不过这里没有上述元素三合一的例子。
设置WEB程序的Preloader为自制的Preloader时,要修改主程序Application标签中的preloader属性,
<?xml version="1.0" encoding="utf-8"?> <MX:APPLICATION xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" preloader="com.ibsol.view.Preloader"> <MX:SCRIPT> ....</MX:SCRIPT></MX:APPLICATION>
这里的com.ibsol.view.Preloader是自定义Preloader类的路径。
Preloader要扩展DownloadProgressBar类才能设置自己的Preloader
package com.ibsol.view { import flash.display.Sprite; import flash.events.Event; import flash.events.ProgressEvent; import flash.events.TimerEvent; import flash.text.TextField; import flash.utils.Timer; import mx.events.FlexEvent; import mx.preloaders.DownloadProgressBar; /** * 自定义加载页面 * */ public class Preloader extends DownloadProgressBar { //显示进度文字 private var progressText:TextField; //进度条 private var img:WelcomeScreen; //logo页面 private var logo:WelcomeLogo; private var _timer:Timer; /** * 初始化方法 * */ public function Preloader() { super(); //将logo添加到当前页面 logo=new WelcomeLogo(); this.addChild(logo); //将进度条添加到当前页面 img=new WelcomeScreen(); this.addChild(img); //加入进度条文字 progressText=new TextField(); progressText.x=40; progressText.y=90; this.addChild(progressText); //进度条计时器初始化,实现进度条的原理就是不停的刷新进度条图片 //因为每次进度条的长度不同,所以就有进度条在走的效果 _timer=new Timer(1); _timer.addEventListener(TimerEvent.TIMER,drawTimerHandler); _timer.start(); } override public function set preloader(value:Sprite):void { value.addEventListener(ProgressEvent.PROGRESS,progHandler); value.addEventListener(FlexEvent.INIT_COMPLETE,initCompleteHandler); //在这里设置预加载页面居中 //如果在初始化函数中设置,会有stageWidht和最终大小不一致的错误,而导致不能居中 x=(stageWidth/2)-(300/2); y=(stageHeight/2)-(180/2); } private function progHandler(evt:ProgressEvent):void { //计算进度,并且设置文字进度和进度条的进度 var prog:Number=evt.bytesLoaded/evt.bytesTotal*100; progressText.text="已下载"+String(int(prog))+"%"; if(img) { img.progress=prog; } } private function compHandler(evt:Event):void {} private function initCompleteHandler(evt:FlexEvent):void { //如果载入完毕,则停止刷新 img.ready=true; _timer.stop(); //这里是测试,下载完毕后,不马上跳到程序默认界面,而是停留10秒后再跳入 var timer:Timer=new Timer(1000,1); timer.addEventListener(TimerEvent.TIMER,dispatchComplete); timer.start(); } private function initProgHandler(evt:FlexEvent):void {} private function dispatchComplete(evt:TimerEvent):void { //一定要分发这个事件,来通知程序已完全下载,可以进入程序的默认界面 this.dispatchEvent(new Event(Event.COMPLETE)); } //计时器监听事件 private function drawTimerHandler(evt:TimerEvent):void { img.refresh(); } } }
图片logo层的实现方法:
package com.ibsol.view { import flash.display.Loader; import flash.utils.ByteArray; /** * 图片logo层 * */ public class WelcomeLogo extends Loader { [Embed(source="img/logo.png",mimeType="application/octet-stream")] public var WelcomeScreenGraphic:Class; /** * 初始化方法 * */ public function WelcomeLogo() { this.loadBytes(new WelcomeScreenGraphic() as ByteArray); } } }
进度条和图片可以放在一层,但是考虑到个时钟周期,都要刷新进度条的图片。
毕竟LOGO不用每次都刷新,那么我们就分开放置了。进度条层的代码如下,
package com.ibsol.view { import flash.display.BitmapData; import flash.display.Graphics; import flash.display.Loader; import flash.display.Sprite; import mx.graphics.codec.PNGEncoder; public class WelcomeScreen extends Loader { //辅助属性,帮助进度条定位 private static var _LogoWidth:int=300; private static var _LogoHeight:int=180; private static var _LeftMargin:int=5; private static var _RightMargin:int=5; private static var _Topmargin:int=1; private static var _BottomMargin:int=1; private static var _Padding:int=-60; //进度条的样式的设定,如边框颜色等 private static var _BarWidth:int=200; private static var _BarHeight:int=12; private static var _BarBackground:uint=0xFFFFFF; private static var _BarOuterBorder:uint=0x737373; private static var _BarColor:uint=0x6F9FD5; private static var _BarInnerColor:uint=0xFFFFFF; private var isReady:Boolean=false; public var progress:Number; private var _logoData:BitmapData; /** * 初始化方法 * */ public function WelcomeScreen() { } override public function get width():Number { return Math.max(_BarWidth,_LogoWidth)+_LeftMargin+_RightMargin; } override public function get height():Number { return _LogoHeight+_LogoHeight+_Topmargin+_Padding; } /** * 进度条加载完毕后,隐藏进度条 * */ public function set ready(value:Boolean):void { this.isReady=value; // this.visible=!isReady; } public function get ready():Boolean { return isReady; } /** * 刷新方法,每个时钟周期都被调用这个函数 * */ public function refresh():void { _logoData=this.drawProgressBar(); var encoder:PNGEncoder=new PNGEncoder(); this.loadBytes(encoder.encode(_logoData)); } /** * 生成进度条函数 * */ public function drawProgressBar():BitmapData { //创建bitmapdata对象 var data:BitmapData=new BitmapData(this.width,this.height,true,0); //画出bitmapdata var s:Sprite=new Sprite(); var g:Graphics=s.graphics; g.beginFill(_BarBackground); g.lineStyle(2,_BarOuterBorder,1,true); var px:int=(this.width-_BarWidth)/2; var py:int=_Topmargin+_LogoHeight+_Padding; g.drawRoundRect(px, py, _BarWidth, _BarHeight, 2); var containerWidth:Number=_BarWidth-4; var progWidth:Number=containerWidth*this.progress/100; g.beginFill(_BarColor); g.lineStyle(1, _BarInnerColor, 1, true); data.draw(s); return data; } } }