首先,想说一下我写此文的动机。记得很早之前我曾经说过“没有loading的flash,不是完整的flash”。我想那个句话可能偏激了。因为有时候一些不到10k的flash,确实不需要做什么loading。但我始终认为,做一个优秀的loading是衡量一个flasher水准,甚至态度的。你问我为什么,我可以告诉你,因为loading是唯一一个你不会多看而所有用户、客户会看的东西,所以你对loading的重视程度,甚至可以反衬你这个flasher的职业道德!
有些做设计为主的朋友,我认识不少,他们对loading都是得过且过的态度,做一个loading,更多的是自己找一个现成的,然后每次去套用,我个人认为是很不好的习惯。并不是说我不提倡代码、元件的重用度,而是我觉得对于loading这种东西,套多了,是要出问题的。我强烈建议那些已经达到可以修改人家loading水平的flasher看看我的东西,当然,如果你连flash的as该写在哪都不知道,建议先入门了。
好,下面切入正题,如何制作loading:
首先要感激Macromedia的大智慧,提供了很好的两个函数使我们可以做出完美的loading,那就是getBytesLoaded和getBytesTotal。请不要再用你改来改去改了两三年的那个什么getFrameLoaded什么什么了,我都记不清楚怎么拼了。我只想说,Frame的观念将在真正的Interactive-Design中淡化。更别提什么Scene,那是Flash的败笔!
那么loading如何工作呢?我们如何利用这两个函数呢?这里要提到一个重要的概念。就是间隔调用。间隔调用有多种方式,下面列举出来,并列举出其在loading制作中的地位和用法,欢迎补充:
·setInterval方式
写法:
function loadCheck()
{
var p = getBytesLoaded()/getBytesTotal();
if (p==1)
{
clearInterval(intervalID); // 释放间隔调用
gotoAndPlay(someFrame); // 开始播放
}
}
var interval = 30; // 这个数值是刷新频率
var intervalID = setInterval(loadCheck,interval);
我个人并不推荐初学者用这种写法。因为很多人容易忽视clearInterval,而这个东西被忽视掉,是很恐怖的!如果你的setInterval没有给及时移除,意味着你将在整个swf的播放过程中增加一个没有必要的负担!
而且这种方法很不适合控制MoiveClip的状况(因为初学者会发现MC的路径是个大问题,而loadCheck本身就是个函数,还是被setInterval调用的,要在loadCheck中指一个路径出来,挺麻烦的,你不要指望_root,那样会让你的程序不规范;也不要指望this,因为在函数中用this似乎不太理想;最好什么都不写,但往往你不敢不写),进而做出更好的效果。
·onEnterFrame方式
我最喜欢的就是这种方法了。比较方便、直观。因为往往我们是要用一个MC体现一个loading的进度,比如,一个进度条,或者更有创意的东西,只有你不能想到的,没有你不能做到的。
那么究竟如何用呢。首先,把创意定好。然后给你的MC一个实例名字,比如叫做loader_mc。这时候在timeline上写代码,记住,是timeline而不是MC上。因为这样便于代码统一、便于路径统一、便于管理和寻找。别为了省几个字母就把代码通通搬到button,mc上面去,然后一个on(press)了事。除非你是在敷衍你的作品;或者你是在为了交作业。
loader_mc.onEnterFrame = function ()
{
var getTar:MovieClip = this._parent;
var p = getTar.getBytesLoaded()/getTar.getBytesTotal();
trace(p);
if(p==1)
{
this.onEnterFrame = null;
gotoAndPlay(someFrame); // 开始播放
}
}
就这么简单,记住,在MC的事件函数体内部引用MC,永远是一件很快的事情。因为this就可以指向这个MC本身,通过诸如this._parent之类的方法,可以找到你所有的MC!
·直接依赖于timeline的循环方式
非常非常非常古老的方式了,不介绍了。不过你们可以去问问那些一直不喜欢自己动手做loading的flasher,他们也许在改的某一个版本就是这个,呵呵。
以上算是比较简单的。比较容易出问题的,还有两个。
第一、MovieClipLoader
第二、含有多种V2组件的Loader
读取外埠数据参与Flash应用程序部署是一件非常重要和常见的工作,尤其是我们常常需要检测这些数据加载的进度。而MovieClipLoader(下称MCL)类却帮我们大大简化了这项麻烦工作。此外,它使得我们能获取更多的需要,并减少代码量。我们可以用一个单独的MovieClip类来载入一个,或者多个外埠资源到指定的MC或者层级,或者我们可以为每一个加载工作制定不同的MCL实例。
我决定分两部分来完成这篇教程。首先,我们将介绍MCL的基本用法;然后我们将介绍如何使用一个单独的MCL实例来读取外埠资源到不同的MC,并且,我们将加入侦听器对象来参与工作。当然,不通过侦听器也可以完成任务,我们暂时不介绍侦听器,因为这样你会更加容易理解MCL。
那么,我们首先来大体了解一下MCL有哪些回调函数,后面也会有详细介绍(aw附:回调函数我个人理解就是某一个类组、参数事先确定,拥有指定功效的方法)这里可以了解一下什么叫做回调函数):
MovieClipLoader对象的回调函数:
事件回调函数(严格要求数据类型的时候,它们并不是方法,后祥):
* MovieClipLoader.onLoadStart() - 当加载开始的时候触发
* MovieClipLoader.onLoadProgress() - 在读取进行中触发
* MovieClipLoader.onLoadInit() - 读取资源载入后的第一帧执行完成后触发
* MovieClipLoader.onLoadComplete() - 当读取的外埠资源已经完全下载到本地时触发。
* MovieClipLoader.onLoadError() - 当加载外埠资源出错时触发。
* MovieClipLoader.unloadClip() - 将加载的外埠资源移除或终止一个加载工作。
方法回调函数:
* MovieClipLoader.getProgress(target:Object):Object - 读取外埠资源的进展,参数为MC对象(aw附:其实MC这种数据类型也就是一种对象)。返回一个对象,该对象包含两种事先预定好的属性(后祥)
要想好好理解这些回调函数,我们动手试验一下是最好的方法。当然MCL是Flash7之后才有的,所以别忘了发布的时候发布成为7+的版本号。如果直接用FlashPlayer来调试可能会遇到一些问题,我们推荐在浏览器中进行调试(个人意见:对于外埠资源难以获得情况,比如教育网获取公网资源,最好不要在IDE中调试)
在我们的例子中,我们将用一个MCL对象来读取不同的图片,并将它们置入不同的空MC中。本例中要用到的swf文件和图像源文件将在Actionscript.org找到(个人建议:其实看完这篇文章要不要源文件没有必要了)
1、建立一个新的Flash文档,并在第1帧输入以下脚本:
_root.traceBox.vScrollPolicy ="on";
function myTrace(msg)
{
_root.traceBox.text += msg + newline;
_root.traceBox.vPosition = _root.traceBox.maxVPosition;
}
我们这里是在建立一种跟踪调试机制,调试的(变量)将输出到文本框组件中。这里的方法"myTrace"是预先定义好的一个函数,它帮助我们顺利完成对某些信息的监控;其中第二句的作用是使文本框随时输出最新监控值。
2、现在从组建库托拽一个TextArea组件进入场景,并给以合适的大小,以及一个实例名称traceBox(对应上面的脚本)
3、接下来,我们要建立一个新的MC元件。并在场景上部署3个实例,为它们分别命名为myMC1,myMC2,myMC3。我们将把图片或者swf影片装载进入它们,并且,在它们下载到本地后按照需求调整它们的尺寸。其实,对图片人为地改变尺寸会造成许多不好的后果,比如锯齿的产生,但是为了让大家了解onLoadInit事件的使用,我们将会这么做。
4、然后,我们建立一个MCL对象,在第一帧输入以下脚本:
var myMCL = new MovieClipLoader();//create an instance of MovieClipLoader
aw附:这里我想罗索以下,关于Object的翻译。因为上述代码的注释中,老外用的是instance这个词,直译的话,Object是“对象”;Instance代表“实例”。前者更注重于其数据类型,而后者则更注重于其客观存在性。
5. 现在我们就可以部署脚本了,在第一帧:
myMCL.onLoadStart = function (targetMC)
{
var loadProgress = myMCL.getProgress(targetMC);
myTrace ("The movieclip " + targetMC + " has started loading");
myTrace("Bytes loaded at start=" + loadProgress.bytesLoaded);
myTrace("Total bytes loaded at start=" + loadProgress.bytesTotal);
}
这个函数的第一行中申明了一个(对象类型的)变量,显然,这个变量的值由myMCL对象的getProgress方法获得.刚才已经介绍了getProgress方法,这里可以看到,返回的loadProgress.bytesLoaded就是loadProgress对象的bytesLoaded属性.
这里我再啰嗦一句:为什么返回一个对象,而不返回具体的值。这是有原因的。函数返回值的功能使得程序设计更加完美,然而很多情况下,我们要返回的并非一个值,我们可能返回两个或者更多的值,甚至它们的数据类型都不相同。这样,只有通过对象的形式来返回了。这是解决问题最简单最高效的方法。下面三句myTrace就呼应了之前我们定义的监控函数,这样就能看到我们关注的变量了。
6、我们已经为onLoadStart事件部署了相应的工作,接下来我们要为上述其他事件部署工作了。紧接着是onLoadProgress,它接受三个参数:targetMC, loadedBytes, totalBytes。分别代表目标容器MC实例;已经读取的体积、总体积。
myMCL.onLoadProgress = function (targetMC, loadedBytes, totalBytes) {
myTrace ("movie clip: " + targetMC);
myTrace("Bytes loaded at progress callback=" + loadedBytes);
myTrace("Bytes total at progress callback=" + totalBytes);
}
7、我们的onLoadComplete方法仅接受一个参数,它就是容器MC实例。像onLoadStart一样,我们用getProgress方法来返回读取情况。
myMCL.onLoadComplete = function (targetMC)
{
var loadProgress = myMCL.getProgress(targetMC);
myTrace (targetMC + " has finished loading.");
myTrace("Bytes loaded at end=" + loadProgress.bytesLoaded);
myTrace("Bytes total at end=" + loadProgress.bytesTotal);
}
8、onLoadInit方法将在所有加载的内容被下载到本地容器MC中之后才开始执行。这将使得你能更好的控制加载进来的内容的属性。我选择的图片非常大,这样我们可以把读取过程看得更加清晰,而我也要对已经加载的图片尺寸进行修整,让它能全部显示出来。
myMCL.onLoadInit = function (targetMC)
{
myTrace ("Movie clip:" + targetMC + " is now initialized");
targetMC._width = 170;
targetMC._height = 170;
}
9、还有一个回调方法onLoadError。如果有错误发生,它将会被触发。作为一个优秀的程序员,部署完善的应用程序的时候,对错误发生的避免措施是必不可少的!
myMCL.onLoadError = function (targetMC, errorCode)
{
myTrace ("ERRORCODE:" + errorCode);
myTrace (targetMC + "Failed to load its content");
}
10. Well that's the hard work out of the way. Now we just have to load the files in to their respective targets, using loadClip, and passing it two arguments: the location of your file, and the destination movieclip for the file to load in to.
10、我们终于将最复杂的工作部署好了。接下来我们只用使用loadClip方法读入我们需要的内容就行了。loadClip方法的两个参数分别是外埠资源的地址和容器MC的实例。
myMCL.loadClip("http://www.yourdomain.com/test1.swf","_root.myMC1");
myMCL.loadClip("http://www.yourdomain.com/test2.swf ", "_root.myMC2");
myMCL.loadClip("http://www.yourdomain.com/pic.jpg", "_level0.myMC3");
路径可以选择相对路径。注意,路径的相对性也是一个大问题,当SWF在非本路径的HTML中被引用的时候,遵从HTML所在的路径!这一点是很多Flash教程都忽视的。所以,有时候绝对路径也有绝对路径的好处。[路径问题源文件下载,下载了就一目了然了
所有的调试工作最好在浏览器中,而非IDE中完成。而且脚本输出方式必须是AS2。
Remember, for everything to work properly you need to be testing throuhg a browser (and preferably on line so you can see the files loading in real time). You also need to be exporting your code as ActionScript 2.
In the second part of this tutorial I'm going to show you how to use the MovieClipLoader class in a real-world situation, in order to solve a common problem when assigning event handlers to Mo