谁都不愿意在加载时看着一片空白的屏幕,于是在网络应用中常常使用到加载进度条、预加载图片等手法来让用户知道你后台正在加载中。
对于进度条的制作,相信大家都从案例一中学习过了,但是却不知道怎么把这样子的进度条应用到实际开发中去。我写教程的目的就是给出各种实用的案例让列位仙家明白在实际开发中如何把学到的知识灵活运用起来,好的,今天咱们就来看看怎么用这进度条吧。
首先,我使用教程一制作出来的进度条swf文件(我采用的是圆形布局的读取动画哦),把它放在我工程目录下,再利用AS中的嵌入标签语句将此swf嵌入进来,记住,所有写有Embed标签的资源都将会在编译时被嵌入flash,会增加编译结果swf的大小,但是该资源不需要在运行时被读取,无需等待,它将会立即显示出来,对于一个进度条来说,我们需要把它嵌在flash中,在flash读取过程中用户将会立即看到进度条在旋转。给出源码:
- package
- {
- import flash.display.Loader;
- import flash.display.MovieClip;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.net.URLRequest;
- [SWF(backgroundColor="0xffffff")]
- public class indeterminateBar extends Sprite
- {
- [Embed(source="LoadingProcessBar.swf")]
- private var loadingProgressClass:Class;
- private var loadingProgressMC:MovieClip;
- private var loader:Loader;
- public function indeterminateBar()
- {
- init();
- }
- private function init():void{
- loader = new Loader();
- loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
- loader.load( new URLRequest("http://www.flash8.net/uploadflash/61/flash8net_60902.swf" ) );
- loadingProgressMC = new loadingProgressClass();
- addChild( loadingProgressMC );
- }
- private function onComplete(event:Event):void{
- removeChild( loadingProgressMC );
- addChild( loader );
- }
- }
- }
一开始我们把进度条资源嵌在loadingProgressClass这个类上,到用的时候就可以直接使用new关键字来创建一个MovieClip的实例了(对于带时间轴的swf文件一般new出来的实例类型为MovieClip,对于.jpg, .png等图片文件,new出来的实例类型一般为BitMap类型)。对于Loader的使用,我在这里不会多提,各位道友可以在很多地方找到关于它的介绍以及用法,这里需要提到的一个关键点在于,我们监听了Loader的COMPLETE事件,它将在Loader加载资源完成时被抛出,当我们监听到此事件时就表示加载已完成了,就可以移去我们之前添加到舞台上的进度条并把加载好资源的Loader添加上去,很简单吧?
运行结果应该是这样子的:
<ignore_js_op>
刚才我们做的是称为不确定型进度条(indeterminate Progress Bar ),这种进度条在读取时用户看不到读取了百分之几,只能看到一个圈圈在转或是某个动画在放啥的。现在为大家介绍一下确定型进度条的制作方式。
对于确定型进度条,它的外观就可以弄得简单些,一般就直接用一根长条就可以了,所以我们先简单地创建一个自定义进度条类:
CustomProgressBar:
- package
- {
- import flash.display.Sprite;
- [SWF(backgroundColor="0xffffff")]
- public class CustomProgressBar extends Sprite
- {
- private var _progressView:Sprite;
- private var _width:Number;
- private var _height:Number;
- public function CustomProgressBar( width:Number = 100, height:Number = 20 )
- {
- super();
- _width = width;
- _height = height;
- initView( );
- }
- public function update( loadedPercent:Number ):void{
- _progressView.width = _width * loadedPercent;
- }
- private function initView( ):void{
- //绘制总进度条轮廓
- this.graphics.lineStyle(1);
- this.graphics.drawRect( 0, 0, _width, _height );
- //初始化进度条视图
- _progressView = new Sprite();
- _progressView.graphics.beginFill(0x0000ff);
- _progressView.graphics.drawRect(0, 0, _width, _height);
- _progressView.graphics.endFill();
- this.addChild( _progressView );
- _progressView.width = 0; //一开始进度条还没开始读取呢,得让它宽度为0才行
- }
- }
- }
这种级别的代码各位应该不会有疑问,所有语句都是以往接触过的。有了这玩意儿我们就可以在主应用中使用之了:
determinateBar.as:
- package
- {
- import flash.display.Loader;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.events.ProgressEvent;
- import flash.net.URLRequest;
- public class determinateBar extends Sprite
- {
- private var loadingProgress:CustomProgressBar;
- private var loader:Loader;
- public function determinateBar()
- {
- init();
- }
- private function init():void{
- loadingProgress = new CustomProgressBar( 200, 40 );
- loader = new Loader();
- loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
- loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
- loader.load( new URLRequest("http://www.flash8.net/uploadflash/61/flash8net_60902.swf" ) );
- addChild( loadingProgress );
- loadingProgress.x = stage.stageWidth / 2;
- loadingProgress.y = stage.stageHeight / 2;
- }
- private function onProgress(event:ProgressEvent):void{
- var loadedPercent:Number = event.bytesLoaded / event.bytesTotal;
- loadingProgress.update( loadedPercent );
- }
- private function onComplete(event:Event):void{
- removeChild( loadingProgress );
- addChild( loader );
- }
- }
- }
唯一需要介绍的地方就是Loader中的PROGRESS事件,当Loader在读取资源时每一定时间间隔内都会抛出此事件,监听此事件并不断更新进度条的外观就可以达到我们的目的啦。
运行结果如下:
<ignore_js_op>
外观比较粗糙,各位别见怪哈,毕竟我又不是美工(- -!自我安慰一下)
接下来,会为各位带来预加载图片的制作方式,会有点复杂哦,学之前请先学习bitMap和bitmapData类的使用方法。
列位仙家,do you miss me? 不好意思,刚去上了个厕所回来,手都没洗就马上敲键盘,准备马上给列位仙家带来我们接下来的案例——图片预加载图像。
所谓预加载图像就是指在图片加载完成前用户在该图片处所看到的图像,为了不让用户看见白白一片的舞台而造成误认为此flash BUG百出的尴尬,使用预加载图像是不错的解决方案。
加载完成前:
<ignore_js_op>
加载完成后:
<ignore_js_op>
再次为这个粗糙的界面抱歉,毕竟我不是……咳咳,后面省略的字不用我说你们都会大声告诉我的对不对?(请回帖告诉我)反正咱们能理解原理就达到目的了,界面有毛用。
首先讲解下预备知识,我们在之前的案例中提到过,使用Embed标签嵌入的资源,new出来的实例类型会有所不同,看下面的代码:
- [Embed(source="wokao.swf")]
- private var wokao:Class;
- [Embed(source="wasai.jpg")]
- private var wasai:Class;
- public function init():void{
- var test1:MovieClip = new wokao(); //资源类型为.swf,实例化结果为MovieClip类型
- var test2:Bitmap = new wasai(); //资源类型为.jpg, .png等图片类型,实例化结果为Bitmap类型
- }
每个bitmap实例都有它所对应的bitmapData, 不过一个bitmapData可以用在好多个bitmap中,所以我们可以嵌入一个预加载图片并使用new操作把它实例化为一个bitmap实例,之后取出此bitmap中的bitmapData,在我们舞台上的图片还未加载完时,它们所对应的bitmapData此时可能为空,那在图片加载完成前,我们可以把预加载图像的bitmapData赋值给它,先一口气把源码都贴上来再说吧:
- package
- {
- import flash.display.Bitmap;
- import flash.display.BitmapData;
- import flash.display.Loader;
- import flash.display.LoaderInfo;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.net.URLRequest;
- [SWF(width="1000", height="800")]//元数据标签,用以设置舞台相关属性
- public class loadingImg extends Sprite
- {
- [Embed(source="assets/preloadImg.jpg")]
- private var preloadImg:Class; //嵌入在swf中的预加载图片类
- private var preloadBMD:BitmapData; //预加载图片的位图数据
- private var imgList:Array; //图片数组
- private var resourceList:Array = ["img1.jpg", "img2.jpg", "img3.jpg"];//资源名称
- private var loadedCount:int = 0;//已加载图片数
- public function loadingImg()
- {
- super();
- init();
- }
- private function init():void{
- preloadBMD = (new preloadImg() as Bitmap).bitmapData;
- var len:int = resourceList.length;
- imgList = new Array( len );//根据要加载图片的数量来决定数组长度
- for(var i:int=0; i<len; i++)
- {
- var bm:Bitmap = new Bitmap( preloadBMD );
- bm.width = 250;
- bm.height = 250;
- bm.x = i * 270;
- bm.y = i * 250;
- imgList[i] = bm;
- addChild( bm );
- }
- loadPicture( "assets/" + resourceList[0] );//若你把资源文件放在一个目录下,前面记得加路径
- }
- private function loadPicture( source:String ):void{
- var loader:Loader = new Loader();
- loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
- loader.load( new URLRequest( source ) );
- }
- private function onComplete(event:Event):void{
- (imgList[loadedCount] as Bitmap).bitmapData = ( (event.currentTarget as LoaderInfo).content as Bitmap ).bitmapData;
- loadedCount++;
- if( loadedCount < resourceList.length ){
- loadPicture( "assets/" + resourceList[loadedCount] );
- }
- }
- }
- }
代码不多,咱们慢慢看。先一眼瞟过所有的import语句以及变量声明,来到我们的init()函数,第一行所做的就是我们刚才提过的,把嵌入的预加载图片实例化后取出其中的bitmapData为我所用。第二句到循环结束这些语句虽然一眼就能看懂,但它们代表了一个提高flash运行效率的好习惯,有的道友喜欢这样使用:
- var array = new Array(); //初始化时不给出数组具体长度
- for(var i=0; i < num; i++)
- {
- array.push(i); //在向数组中添加元素时使用array.push语句
- }
更好的写法应该是:
- var array = new Array( num ); //初始化时给出数组具体长度
- for(var i=0; i < num; i++)
- {
- array[i] = i; //在向数组中添加元素时直接对数组中每个元素赋值
- }
在数组中元素数量庞大时,后者执行效率比前者快很多,不信你大可以试试,不过后者仅限于知道数组长度的情况下使用哦。还有一点,相信细心的道友们已经发现了,就是我在循环开始前先求出了数组resourceList的长度再把此长度放到了循环的限制条件中,这样写的效率高于这样写:
- for(var i:int=0; i<resourceList.length; i++){}
为啥捏?因为这样写的话每次循环都会去计算一下resourceList.length的值,很浪费时间。
在循环中,我们根据要加载的图片数量创建出一定的bitmap实例并添加到舞台上,给这些bitmap实例构造函数中填入我们刚才提取出来的预加载图片的bitmapData,让他们的bitmapData在创建时就等于预加载图片的bitmapData,这样它们一被添加到舞台上就会立即显示预加载图片的样子了。
在loadPicture()方法中我使用了循环加载的概念,一个图片加载好后会立即加载下一个,给loader的COMPLETE事件添加侦听,当图片加载完成后触发此事件,捕捉到此事件时我们把加载好的图片从LoaderInfo.content中拿出来,在给他实例化为bitmap后把他有价值的玩意儿(即它的bitmapData)剥夺出来替换之前的预加载图片的bitmapData,做完这些后别忘了继续下一步加载哦。
好了,一口气讲了很多了,若各位还有什么不懂的直接回帖发问哈,我会第一时间解答你的哦 ~_^
为了给弟兄们省银子,我把所有文件都打包在一起了,请笑纳~其中的img1 ~ img3 三张图片太大了,附件不允许这么大,于是就被我KO掉了,请各位直接去找三张图片放到assets目录下并改成和程序中一致的名字吧~
<ignore_js_op> PreLoading.rar (1.16 MB, 下载次数: 1162)