1、线性化下载过程

一般的下载队列,是一口气推入n个loader,然后逐个下载,下载完了调用start,开始整个程序。

由于是线性过程,这个时候下载流程比较好控制。假如碰到被下载的一个swf中,又下载别的图片、音乐之类,就成了树形过程了。LoaderMax在这方面的处理是利用一个requireWithRoot 属性,指定该Loader隶属于哪个容器。一旦指定,那么这个Loader所下载内容,就当作容器的一部分。

比如 main.swf > (a.swf > a.mp3) > (b.swf > b.jpg), a.mp3 和 b.jpg都远大于两个swf。

当main在下载的时候,先下a.swf,完了下b.swf。而a.swf中会去下载a.mp3,b.swf则是下载b.jpg。所以很可能出现的情况是a,b.swf都下载好了,还在同时下载a.mp3和b.jpg。但这个时候main已经算下完了,要start了...

如果在a.swf下载a.mp3时设置requireWithRoot = root,b.swf也一样。那么main.swf在a.swf之后下a.mp3,直到a.mp3下载完了,才算a.swf下完。这样就把一个树形流程又改为线性的了。

2、预估文件大小

在下载文件时,都知道有个请求过程,这个过程中文件的总大小是不知道的。这样对显示进度就是个麻烦事儿。像以前碰到公司内网关上安了2b防火墙,进来的数据都隔那儿堵着,等cache满到一定大小才一下子返回。搞得每次在公司看loading都是一闪而过,这不是因为快,是因为前面堵着呢,只能傻等着....LoaderMax在这方面采用了预估文件大小,利用一个estimatedBytes 属性,先假设要下的文件大小是多少。这样一来,即使请求还没来,下载进度还是有的。如果网络不出问题,等到请求返回了,马上就拿精确的文件大小替换预估值,让进度始终保持在用户眼前,而不会傻等。这个属性的默认大小是 20000 (20k)。

3、tween式初始化

这个就不多说了,还是那句话,没用过TweenLite、TweenMax的人还有么?

4、显示对象的对齐

显示对象在下载后有个比较恼人的问题,就是定位和对齐。这个问题其实已经被TransformManager 很好的解决掉了。LoaderMax只是让操作更简单了。

只需在初始对象的属性里面增加width,heighth或scaleX,scaleY(前者优先权大于后者)再配合scaleModes属性就很轻松了。

5、选择性打包

实际上LoaderMax并不是一个万能下载器,他只是一个壳儿,具体的下载交给SWFLoader,XMLLoader,MP3Loader...等等,这样的话,项目中要啥就选啥,可以节约文件大小。编译的时候也不会浪费不必要的时间。

6、并行下载

一般的下载队列,就是逐个下载吧?LoaderMax有个maxConnections 属性,可以设置同时下载数。默认为2。

7、下载信息

还有件比较烦人的事情,就是在定义一个loader后,有时候还要再为之定义个变量,指向下载对象。该指向还必须得在下载好以后才能设置。

这点LoaderMax也封装掉了。LoaderMax.getContent(),而且由于Loader事先就是有类型信息的,像CSSLoader,MP3Loader,所以content在使用上有着很高的可读性。


LoaderMax类的使用指导


1、SWFLoader和ImageLoader的content 和rawContent有何不同?
       content属性取得的是包含了真实内容的容器,而rawContent取得的是真实加载内容。这样做的一个主要原因是在真实的内容加载完成之前就能添加到显示列表或者添加其他的事件。

       真实内容(rawContent)可以是图片、MovieClip、Loader或者Video,所以包装的容器也提供也提供一致的对象类型。同时还提供一些非常方便的缩放和裁剪功能。所以你一般使用content属性就行了,除非你需要直接访问SWFLoader和ImageLoader加载的真实内容。

       下面提供一个简单的例子:

    var loader:SWFLoader = new SWFLoader("child.swf",
                                         {onComplete:onLoadSWF, width:200, height:100});      

    //加载开始之前就可以添加到显示列表
    addChild(loader.content);
    loader.load();    
    function onLoadSWF(event:LoaderEvent):void {
var mc:MovieClip = loader.rawContent; //取得真实的内容并调用他的一个函数
       mc.myCustomFunction();    里调用了加载到的swf中的一个类
    }

2、随心所欲的使用单独的加载器
如下面的例子一样,如果你只是要加载一个swf文件,则可以直接使用SWFLoader而无需使用LoaderMax进行包装。
//以下方式完全将swfLoader当做类似于Loader一样用了
var loader:SWFLoader = new SWFLoader("child.swf", {onComplete:completeHandler});
loader.load();
//addChild(loader) 直接添加到显示列表没有任何问题

//用上面的代码方式就行了,不需要像下面这样
var queue:LoaderMax = new LoaderMax({onComplete:completeHandler});
queue.append( new SWFLoader("child.swf") );
queue.load();

当你有多个loader需要加载的时候才应该考虑将loader放入到LoaderMax里面。LoaderMax会管理列表中的每一个loader,汇报他们的进度。

3、在XML中定义你要加载的文件
你知道吗,XMLLoader会在你加载的XML文件中自动查找LoaderMax关联的数据,并根据你的定义自动创建正确实例来加载他们。例如,你可以在XML数据中定义两张需要自动加载的图片。

首先定义一个xml文件:

<?xml version="1.0" encoding="iso-8859-1"?>
<data>
    <ImageLoader url="1.jpg" name="p_w_picpath1" load="true" />
    <ImageLoader url="2.jpg" name="p_w_picpath2" load="true" />
</data>

下面你的加载代码:

LoaderMax.activate([ImageLoader]); //这一句其实是为了引入ImageLoader这个类
var loader:XMLLoader = new XMLLoader("data.xml", {onComplete:completeHandler,estimatedBytes:50000});
loader.load();

function completeHandler(event:LoaderEvent):void
{
  var p_w_picpath1:Bitmap = LoaderMax.getLoader("p_w_picpath1").rawContent;
  var p_w_picpath2:Bitmap = LoaderMax.getLoader("p_w_picpath2").rawContent;
}

下面让我们在XML文件中定义两个LoaderMax节点,第一个自动加载一个不自动加载。在这里我们通过设置prependURLs 属性定义一个基本的url,可以让后面录入简化。

下面是需要加载的XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<data>
   <LoaderMax name="queue1" prependURLs="
http://www.greensock.com/assets/p_w_picpaths/" load="true">
       <ImageLoader url="1.jpg" name="p_w_picpath1" width="200" height="150" scaleMode="proportionalInside" alpha="0" />
       <ImageLoader url="2.jpg" name="p_w_picpath2" width="400" height="300" scaleMode="proportionalOutside" crop="true" />
   </LoaderMax>
   <LoaderMax name="queue2" prependURLs="
http://www.greensock.com/assets/" load="false">
       <SWFLoader url="swf/child.swf" name="child" autoPlay="false" />
       <VideoLoader url="video/video.flv" name="video" width="400" height="300" scaleMode="stretch" autoPlay="false" />
   </LoaderMax>
</data>

接下来的ActionScript里,XMLLoader将自动解析所有的加载器,不过只会自动加载第一个LoaderMax节点中的内容,因为他的"load"属性设置为"true"。xmlloader加载完成之后,这些内容也完成了加载。我们还可以继续加载第二个LoaderMax中的内容。代码如下:

LoaderMax.activate([ImageLoader, SWFLoader, VideoLoader]);
var loader:XMLLoader = new XMLLoader("data.xml", { onComplete:completeHandler, estimatedBytes:50000 } );

function completeHandler(event:LoaderEvent):void {
   trace("XML and queue1 loaded!");
   addChild( LoaderMax.getContent("p_w_picpath1") );
   addChild( LoaderMax.getContent("p_w_picpath2") );
   //grab the LoaderMax named "queue2" that was defined in the XML and start loading it now
//取得xml文件中名字为"queue2"的LoaderMax开始加载
   var queue2:LoaderMax = LoaderMax.getLoader("queue2");
   queue2.addEventListener(LoaderEvent.COMPLETE, queue2CompleteHandler);
   queue2.load();
}

function queue2CompleteHandler(event:LoaderEvent):void {
   trace("queue2 loaded!");
}

4、简单的进度条设置
LoaderMax里获取精确的加载进度实在是简单到不能再简单了,你只要设置你的进度条对象bar.scaleX=progress就搞定了。

代码如下:

var queue:LoaderMax = new LoaderMax({onProgress:progressHandler});
//...append various loaders...
queue.load();

function progressHandler(event:LoaderEvent):void {
   myProgressBar.scaleX = event.target.progress;
}

5、统计下载速率或者耗时
LoaderMax里每一个加载器(loader)都有一个loadTime属性,他会告诉你加载中消耗了多少时间,你也可以用来计算下载速率。

var kbps:Number = (loader.bytesLoaded / loader.loadTime) / 1024;
trace("下载速率为:"+kbps)

如果计算完成下载需要多长时间可以这样:

var secondsLeft:Number = (1 / loader.progress) * loader.loadTime;

6、让video/p_w_picpath/swf 的大小适应区域
这是一种比较常见的需求,有一个固定了大小的区域,你需要让加载进来的video/p_w_picpath/swf适应区域的大小。比如:你有一个缩略图的网格,但是你的实际图片大小与缩略图的规定大小并不一致或者是未知的。没问题,你可以直接设置图片的宽度和高度来适应你的区域大小。

var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, container:this});

默认情况下他会通过拉伸来适应你设置的尺寸。如果你希望按照比例来缩放显示以适应区域,可以设置scaleMode属性为“proportionalInside”. 这种情况下水平或者垂直方向可能会多出空余位置,你可以设置“hAlign” and “vAlign” 属性来确定水平适应还是垂直适应(默认值都为"center")。如果你希望改变区域的填充颜色可以设置"bgColor"属性。

下面的例子是将图片加载到一个200*100红色背景的区域中,等比缩放,并设置x和y位置属性:

var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, scaleMode:"proportionalInside", bgColor:0xFF0000, container:this, x:50, y:70});

还有一个好处是放置图片的ContentDisplay对象会立即创建,你可以放在场景的任何位置,添加鼠标事件等等(意思就是说创建一个p_w_picpathLoader实例后不用等加载就能马上设置)。例如添加一个鼠标事件可以这样来写:

loader.content.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
   trace("clicked p_w_picpath associated with loader: " + event.currentTarget.loader);
}

重要提示:
如果你想改变区域的尺寸到缩放后的内容的尺寸,可以设置ContentDisplay的"fitWidth"和"figHeight"属性。

7、设定区域对p_w_picpath/video/swf进行裁剪
假设你想让一张图片等比缩放以适应到某个区域,但是不希望在区域的边缘留下空白区。怎么做?你可以首先设定scaleMode属性为"proportionalOutside",然后将"crop"属性设置为true。这样可以使图片等比填充整个区域,并且讲超出区域的部分裁剪掉。下面给一段代码:

var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, scaleMode:"proportionalOutside", crop:true, container:this, x:50, y:70});

8、progress 和 rawProgress有什么不同?(译者注:这个特性需要特别了解)
所有的加载器都有一个"progress"属性来显示"bytesLoades"和"bytesTotal"的比例(即进度)。但是LoaderMax类还多了一个"rawProgress"的属性,这个属性将所有的加载文件同等对待而且与文件大小无关。它在一些特定的场合下会比较有用:比如你发现你的进度条不稳定或者你想忽略文件大小的评估同时不想给你的加载器设定estimatedBytes 。

下面有个例子,可以让你充分了解"progress"和"rawProgress"在各种情景下的比较。你会发现"rawProgress"进度条不会突变,但是相对于以文件大小为计算依据的方式速度会一会儿快,一会儿慢。
点击load()按钮你可以看到"progress"非常精确并且平滑。(这是因为estimatedBytes的值是正确的)接下来你试着改变estimatedBytes的值或者删除estimatedBytes的值看一下省略的时候的运行情况。试着取消“auditSize”的复选框,可以观察“auditSize”为false的情况下是如何运行的。更多有关进度条暴增和回退的问题原因会在下一节做讲解。



9、避免进度条的抖动(暴增或者回退)
不知道你有没有在使用中遇到过进度条暴增活着回退的情况。一般在单一加载的时候不会出现这种情况,但是当你用一个LoaderMax实例去加载多个文件的一些特殊场合会发生这种情况。首先说一下原因和我所使用的方案。

为了精确的计算一组加载器总的进度,我们最关键的是需要知道每一个文件的文件大小。但是在文件还没有开始加载的时候我们如何知道要加载的大小呢?LoaderMax通过两种方式来处理:第一种——在创建你的loader的时候随意指定一个值给"estimatedBytes"属性,就像这样:

newImageLoader("1.jpg", {estimatedBytes:26000});

如果你给一个加载器设定了一个"estimatedBytes"值,LoaderMax会根据这个值来计算"progress",直到开始真正加载取到了真实的文件大小值再替换掉它。如果你所设定的值不准确,就会在修正这个文件大小值的时候出现进度条的抖动。具体现象为:如果你所设定的值比真实的文件大小值小很多,就会出现进度条的回退。如果你所设定的值比真实的文件大小值大很多,就会出现进度条的暴增现象。

LoaderMax所采用的第二种解决方式是检查真实文件。默认情况下会查找每一个子加载器是否有"estimatedBytes"设置。一旦发现没有进行设置,就会迅速开启一个URLStream取得真实的文件大小,并立刻关闭再检查下一个。全部检测完毕后,就会按照真实的文件总字节数加载并计算进度。这样做的好处是减少了你的麻烦并且会进度会非常准确。不过会要在开始下载前花费一些检查的时间。

当然你也可以关闭"auditSize"选项或者进行全局设置关闭所有加载器的"auditSize",下面是代码:

var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, //turns auditing off for only this instance:
var queue:LoaderMax = new LoaderMax({auditSize:false});

//changes the default auditSize to false for all LoaderMax instances created after this point
LoaderMax.defaultAuditSize = false;height:100, scaleMode:"proportionalOutside", crop:true, container:this, x:50, y:70});

好了,知道了原因下面我们来看一下如何解决,这里有一些方案共你选择:
比较省事、精确、需要一点额外时间(默认)的方式
忽略estimatedBytes 选项,让LoaderMax自己去计算。

给一个估计的文件大小值设置到estimatedBytes
这种方式需要给一个合适的值,否则过大进度条会暴增,过小进度条会回退。

比较省事、非常不精确、无需额外时间
关闭自动校验长度开关也不给默认的文件大小值,此时文件长度会使用默认的20000字节为长度。

省事、比较精确、无需额外时间
关闭自动校验长度开关改用"rawProgress"来代替"progress"。由于rawProgress的计算方式与文件长度有关仅与文件个数有关,所以没有必要校验文件长度了。

10、每一个文件都会请求两次吗?
不是这样的。事实上只有当你没有设置estimatedBytes并且自动校验长度开关打开的情况下才需要请求两次服务器。多出的这一次是用于校验文件长度的。

11、集成roo swf到LoaderMax进度
加入你要获取一个很大的swf文件,还需要加载很多素材,同时你还希望了解所有这些的进度(包括这个root Swf)。你可以这样来做:

var queue:LoaderMax = new LoaderMax({onProgress:progressHandler, onComplete:completeHandler});
queue.append( new SelfLoader(this) ); //just to include the root swf in the progress calculations
queue.append( ...append your other loaders... );
queue.load();

12、parse()一个完整的Url数组
有时候你会希望简单的给LoaderMax一个数组,让它自己使用对应的类型去加载。可以用下面的方法来做:

var urls:Array = ["1.jpg", "video.flv", "child.swf", "audio.mp3"];

//activate the types of loaders so that parse() can recognize the appropriate extensions (only necessary once)
LoaderMax.activate([ImageLoader, VideoLoader, SWFLoader, MP3Loader]);

var queue:LoaderMax = LoaderMax.parse(urls, {onComplete:completeHandler}, {autoPlay:false});
queue.prependURLs("http://www.greensock.com/assets/"); //saves us from having to include this in every URL in the array, and makes switching servers very easy.
queue.load();

取得加载的内容用下面的方法:

function completeHandler(event:LoaderEvent):void {
var video:VideoLoader = LoaderMax.getLoader("http://www.greensock.com/assets/video.flv");
addChild( video.content );
video.playVideo();
}

13、取得代码提示和严格的数据类型
如果你不介意文件长度稍微会长一点、代码量会大一些。可以使用 com.greensock.loading.data包里面的类来设定值对象,并作为参数传给记载器。比如:

var config:LoaderMaxVars = new LoaderMaxVars();
config.name = "queue1";
config.onComplete = completeHandler;
config.onProgress = progressHandler;
config.maxConnections = 1;
var queue:LoaderMax = new LoaderMax(config);