发新话题
打印

[技术] 原创-完美的loading-吐血整理!

原创-完美的loading-吐血整理!

共三部分:+ F& m/ V# I8 |' o& v- x: g
1、基础2 A) k( M/ e! F5 L8 X6 x9 H1 h! W
2、MovieClipLoader相关讨论(较深入)
* \0 x/ J# H7 g: y6 @+ f3、V2组件相关问题
2 g9 d8 Z0 P; X5 c
0 J( ?$ P0 J, h1 ^5 c, k一、基础
% ~% Y( w7 h! t% ]' k% f) d很久没有发技术日志了,要来就来个完美的。您别激动,一个小小的loading谈什么完美,我想你看了就知道^_^
2 Y" B" V6 D. r4 N& u" Z9 s2 o我的口号,将此文打造成全球最完善的非Flash初学者loading教程贴。9 e3 R+ M- x/ N. J% u! B; y4 d
转载请保留原文地址:http://www.awflasher.com/blog/?id=444
0 U3 H; C' i% O% t; t5 H6 w! Y$ {1 I1 j$ a$ C" U
首先,想说一下我写此文的动机。记得很早之前我曾经说过“没有loading的flash,不是完整的flash”。我想那个句话可能偏激了。因为有时候一些不到10k的flash,确实不需要做什么loading。但我始终认为,做一个优秀的loading是衡量一个flasher水准,甚至态度的。你问我为什么,我可以告诉你,因为loading是唯一一个你不会多看而所有用户、客户会看的东西,所以你对loading的重视程度,甚至可以反衬你这个flasher的职业道德!
7 L' U  ?' _' |
4 S2 d* B1 y! L& c, l有些做设计为主的朋友,我认识不少,他们对loading都是得过且过的态度,做一个loading,更多的是自己找一个现成的,然后每次去套用,我个人认为是很不好的习惯。并不是说我不提倡代码、元件的重用度,而是我觉得对于loading这种东西,套多了,是要出问题的。我强烈建议那些已经达到可以修改人家loading水平的flasher看看我的东西,当然,如果你连flash的as该写在哪都不知道,建议先入门了。/ ^: r4 O6 E# b1 G

8 s3 j/ J/ l' R$ d+ Q好,下面切入正题,如何制作loading。  t8 v3 A4 E5 a. A
: k# I( r/ T. {# v, t7 x; r
首先要感激Macromedia的大智慧,提供了很好的两个函数使我们可以做出完美的loading,那就是getBytesLoaded和getBytesTotal。请不要再用你改来改去改了两三年的那个什么getFrameLoaded什么什么了,我都记不清楚怎么拼了。我只想说,Frame的观念将在真正的Interactive -Design中淡化。更别提什么Scene,那是Flash的败笔!
' X8 Q& a* C( W4 X
0 m2 z1 h9 ^( v. g) m# `" T" ]& n那么loading如何工作呢?我们如何利用这两个函数呢?这里要提到一个重要的概念。就是间隔调用。间隔调用有多种方式,下面列举出来,并列举出其在loading制作中的地位和用法,欢迎补充:
) _- V1 r/ z+ [8 b- f; o8 L" C6 k) g
·setInterval方式) g% M! ~4 v" o9 I, A  _3 `
写法:$ t( X* p6 z% d
function loadCheck()
2 d( n8 I- {, C" e' H7 ]. k{
! _" F. Q6 ]  d5 e+ m6 A' q8 v/ J  var p = getBytesLoaded()/getBytesTotal();/ @: X* s' b% H7 J. |, h/ i
  if (p==1)
5 U& ]4 ?# E4 f4 @  {) o/ {8 W  h7 t4 r
    clearInterval(intervalID); // 释放间隔调用
- Q$ }/ t( O% D2 L9 T! A4 X    gotoAndPlay(someFrame); // 开始播放
+ ~0 U+ M6 w: h2 w* r  }
' X, r7 C+ C7 d' q  r) p}
: G6 ?. k/ Z3 V' N0 Evar interval = 30; // 这个数值是刷新频率/ N: e! M5 d- ^5 `, ]1 {
var intervalID = setInterval(loadCheck,interval);
$ [- Z# o4 U$ t  M5 u3 C* F5 P9 L9 Z; I* H, j4 X; \6 W. `5 m' ]# z/ Y
我个人并不推荐初学者用这种写法。因为很多人容易忽视clearInterval,而这个东西被忽视掉,是很恐怖的!如果你的setInterval没有给及时移除,意味着你将在整个swf的播放过程中增加一个没有必要的负担!
  q, h  f- |% K1 \而且这种方法很不适合控制MoiveClip的状况(因为初学者会发现MC的路径是个大问题,而loadCheck本身就是个函数,还是被 setInterval调用的,要在loadCheck中指一个路径出来,挺麻烦的,你不要指望_root,那样会让你的程序不规范;也不要指望 this,因为在函数中用this似乎不太理想;最好什么都不写,但往往你不敢不写),进而做出更好的效果。
  n: J* M6 K0 [6 c! r( W/ |% ]; ^% k; F$ h1 a
·onEnterFrame方式7 n" [, |# H1 k6 _3 O
我最喜欢的就是这种方法了。比较方便、直观。
3 ?4 N1 F/ A0 y  x* i! J6 {. B因为往往我们是要用一个MC体现一个loading的进度,比如,一个进度条,或者更有创意的东西,只有你不能想到的,没有你不能做到的。
6 d! j" R+ p$ m. `那么究竟如何用呢。首先,把创意定好。然后给你的MC一个实例名字,比如叫做loader_mc。这时候在timeline上写代码,记住,是 timeline而不是MC上。因为这样便于代码统一、便于路径统一、便于管理和寻找。别为了省几个字母就把代码通通搬到button,mc上面去,然后一个on(press)了事。除非你是在敷衍你的作品;或者你是在为了交作业。
& K5 G- u4 I! o1 ~loader_mc.onEnterFrame = function ()
7 p7 @9 w" ]5 B7 u9 s{
+ p$ ]4 g5 i! n8 v, B9 \. r  R$ ?  var getTar:MovieClip = this._parent;
! o# o& n% h% x  G  var p = getTar.getBytesLoaded()/getTar.getBytesTotal();0 i' v( j7 U: W1 A
  trace(p);; W/ Y/ M$ c1 o6 `/ y
  if(p==1)# [, `3 V$ v( n6 C. Q
  {: A: n0 L- ^' ~6 L
    this.onEnterFrame = null;
8 G# N3 S- L& j; W3 O% }: _6 c    gotoAndPlay(someFrame); // 开始播放* V7 Q" E; M0 t# V  g$ G
  }
% v" ?5 k. ^5 v% o
) D- U( U; d" p# J* V' L}
% {+ R" T8 t- r" v, `
3 O* G; L$ b: t# j7 T就这么简单,记住,在MC的事件函数体内部引用MC,永远是一件很快的事情。因为this就可以指向这个MC本身,通过诸如this._parent之类的方法,可以找到你所有的MC!
9 S4 _, P4 e8 G7 f* K
6 J, K5 d8 y/ o) h; W·直接依赖于timeline的循环方式7 a* X5 H* z" R5 ~3 Z1 T- `
非常非常非常古老的方式了,不介绍了。不过你们可以去问问那些一直不喜欢自己动手做loading的flasher,他们也许在改的某一个版本就是这个,呵呵。
2 i3 R, ^) Z& I( `4 i  Q5 u  l8 p0 D/ Z0 D" w- p, T
以上算是比较简单的。比较容易出问题的,还有两个。
" X0 F* m# l1 _( B1 y第一、MovieClipLoader6 `: d7 n" P8 f6 U
第二、含有多种V2组件的Loader8 I: h+ O! a( y; Q) @9 g1 ]
4 B2 |: U, @  }/ a+ Z
================================: D) J, J0 X( l2 K# Z2 ^4 J2 J

# H8 X; B1 h- Z' i/ g二、MovieClipLoader类说明
3 o% x& x9 `( h& D8 w- \" a1 q- u) F( B& W( j% K) w4 F- ?1 P
. b8 N, i+ x" x; H9 d+ O+ J0 w# W7 ]
参考英文教程,并作出大量原创补充 - Neil Webb, neil AT nwebb DOT co DOT uk, http://www.nwebb.co.uk
# D" b2 n+ g# N+ G) E转载请注明原帖:http://www.awflasher.com/blog/?id=468
# j* _0 z) e8 S: d2 ]* P" B$ Z+ Z6 I- ~, E# l- ~
读取外埠数据参与Flash应用程序部署是一件非常重要和常见的工作,尤其是我们常常需要检测这些数据加载的进度。而MovieClipLoader(下称 MCL)类却帮我们大大简化了这项麻烦工作。此外,它使得我们能获取更多的需要,并减少代码量。我们可以用一个单独的MovieClip类来载入一个,或者多个外埠资源到指定的MC或者层级,或者我们可以为每一个加载工作制定不同的MCL实例。
  X1 K* i0 E! R& }( ^, ]
0 ]6 `& `( p. U我决定分两部分来完成这篇教程。首先,我们将介绍MCL的基本用法;然后我们将介绍如何使用一个单独的MCL实例来读取外埠资源到不同的MC,并且,我们将加入侦听器对象来参与工作。当然,不通过侦听器也可以完成任务,我们暂时不介绍侦听器,因为这样你会更加容易理解MCL。; a4 U" N$ y5 y7 ]( Z
8 C$ D0 l- U* o2 i( {* Z. G
那么,我们首先来大体了解一下MCL有哪些回调函数,后面也会有详细介绍(aw附:回调函数我个人理解就是某一个类组、参数事先确定,拥有指定功效的方法)这里可以了解一下什么叫做回调函数):
  f8 a4 ~" t; Q  Y7 f9 A! G4 v7 P5 O
MovieClipLoader对象的回调函数:
+ Q( u, s$ C+ D! A4 d
  U* A& a9 K0 G! J! z" e( `事件回调函数(严格要求数据类型的时候,它们并不是方法,后祥):
7 Y# k7 o- _' N+ v- G9 b( {! d5 k1 J* MovieClipLoader.onLoadStart() - 当加载开始的时候触发
: Z; q/ c$ S/ B* C* D  W* MovieClipLoader.onLoadProgress() - 在读取进行中触发
8 M; a  F) F% ?; _. E6 u* MovieClipLoader.onLoadInit() - 读取资源载入后的第一帧执行完成后触发
( b& S5 v. p5 T( ]* MovieClipLoader.onLoadComplete() - 当读取的外埠资源已经完全下载到本地时触发。! [! t3 w* w9 G* b9 H/ V/ J
* MovieClipLoader.onLoadError() - 当加载外埠资源出错时触发。
1 a: j1 f* i5 a: f4 M* MovieClipLoader.unloadClip() - 将加载的外埠资源移除或终止一个加载工作。% ]$ w8 ]* Y" u8 W5 s- L
% c1 u% ]5 J) p7 g, x# E) q; g
方法回调函数:
5 I) a, ^' T- r. o" [& Y5 ^* MovieClipLoader.getProgress(target:object):object - 读取外埠资源的进展,参数为MC对象(aw附:其实MC这种数据类型也就是一种对象)。返回一个对象,该对象包含两种事先预定好的属性(后祥)
  ?, @4 M: E" u* c. E8 O4 f4 M+ n
- S+ Y) n+ q1 x. V( w要想好好理解这些回调函数,我们动手试验一下是最好的方法。当然MCL是Flash7之后才有的,所以别忘了发布的时候发布成为7+的版本号。如果直接用 FlashPlayer来调试可能会遇到一些问题,我们推荐在浏览器中进行调试(个人意见:对于外埠资源难以获得情况,比如教育网获取公网资源,最好不要在IDE中调试)
2 T4 X+ D" a1 M4 T0 ^. T
: ?5 O8 b4 L$ T* I在我们的例子中,我们将用一个MCL对象来读取不同的图片,并将它们置入不同的空MC中。本例中要用到的swf文件和图像源文件将在Actionscript.org找到(个人建议:其实看完这篇文章要不要源文件没有必要了)
/ {/ ~: V' Y+ Y6 \2 @. q
0 E8 z7 D% M6 Z$ d7 S. |  O, Y" {==========9 o" b' l7 Y1 l- i7 U

/ R- y0 o) d& w7 U( C9 c! S1、建立一个新的Flash文档,并在第1帧输入以下脚本:* h, P4 N, ^% R  [7 t2 u2 j  ]' R
_root.traceBox.vScrollPolicy ="on";, Q: K2 b+ w2 {% U! \) }4 E, ?
function myTrace(msg); o& G" }/ |! {3 A$ J+ \
{* Z& F6 F( v8 C: q& N8 s
_root.traceBox.text += msg + newline;
8 m3 Y1 w6 z9 v; d' H) x_root.traceBox.vPosition = _root.traceBox.maxVPosition;8 n) Y5 V  a$ C1 w* ?5 z
}
* N4 L$ q3 m* ^+ U; q3 m我们这里是在建立一种跟踪调试机制,调试的(变量)将输出到文本框组件中。这里的方法"myTrace"是预先定义好的一个函数,它帮助我们顺利完成对某些信息的监控;其中第二句的作用是使文本框随时输出最新监控值。& U6 l- W: t" Z, z! v: r
3 c! F& L5 m; ^% W% r- d: _
2、现在从组建库托拽一个TextArea组件进入场景,并给以合适的大小,以及一个实例名称traceBox(对应上面的脚本)
, e5 m$ n7 N, o. V4 E1 o8 h5 u4 k' y! O" C
3、接下来,我们要建立一个新的MC元件。并在场景上部署3个实例,为它们分别命名为myMC1,myMC2,myMC3。我们将把图片或者swf影片装载进入它们,并且,在它们下载到本地后按照需求调整它们的尺寸。其实,对图片人为地改变尺寸会造成许多不好的后果,比如锯齿的产生,但是为了让大家了解 onLoadInit事件的使用,我们将会这么做。
- _2 K9 N& R2 H6 q1 w$ Z0 F4 p/ [% k( K. ?
4、然后,我们建立一个MCL对象,在第一帧输入以下脚本:
& n2 A2 l2 G8 y  G6 }: T1 _var myMCL = new MovieClipLoader();//create an instance of MovieClipLoader' u) y5 [; L) o, y
aw附:这里我想罗索以下,关于Object的翻译。因为上述代码的注释中,老外用的是instance这个词,直译的话,Object是“对象”;Instance代表“实例”。前者更注重于其数据类型,而后者则更注重于其客观存在性。! r+ q9 ]& j% u; u
* {, C8 m, ^$ `5 ^/ v
5. 现在我们就可以部署脚本了,在第一帧:4 t9 i9 d' H3 X3 Y4 g3 B* c
myMCL.onLoadStart = function (targetMC)1 R) u- Q& l% e2 S$ L' h1 M* w6 T
{
: a/ ?5 K/ {3 R6 M1 I3 h! ?var loadProgress = myMCL.getProgress(targetMC);
6 k( ^" D; b8 i% lmyTrace ("The movieclip " + targetMC + " has started loading");1 E% ^, }% \3 p' p
myTrace("Bytes loaded at start=" + loadProgress.bytesLoaded);, U8 Z; f; W' G0 ^5 y
myTrace("Total bytes loaded at start=" + loadProgress.bytesTotal);
# g- ]5 J. `! F}, T1 Z: L. {  R- M* {
这个函数的第一行中申明了一个(对象类型的)变量,显然,这个变量的值由myMCL对象的getProgress方法获得.刚才已经介绍了 getProgress方法,这里可以看到,返回的loadProgress.bytesLoaded就是loadProgress对象的 bytesLoaded属性.
- w1 P- z3 z3 B% H( v这里我在啰嗦一句:为什么返回一个对象,而不返回具体的值。这是有原因的。函数返回值的功能使得程序设计更加完美,然而很多情况下,我们要返回的并非一个值,我们可能返回两个或者更多的值,甚至它们的数据类型都不相同。这样,只有通过对象的形式来返回了。这是解决问题最简单最高效的方法。下面三句myTrace就呼应了之前我们定义的监控函数,这样就能看到我们关注的变量了。6 J" E* c0 R) m, e0 G

) A4 w: w' a; b$ T. W3 j% D2 k6、我们已经为 onLoadStart事件部署了相应的工作,接下来我们要为上述其他事件部署工作了。紧接着是onLoadProgress,它接受三个参数: targetMC, loadedBytes, totalBytes。分别代表目标容器MC实例;已经读取的体积、总体积。
5 l8 @$ d. H! Z* h3 bmyMCL.onLoadProgress = function (targetMC, loadedBytes, totalBytes) {
( I: p* V. R( ~8 m$ V) ^- YmyTrace ("movie clip: " + targetMC);; a2 k+ y5 \9 G, u# D
myTrace("Bytes loaded at progress callback=" + loadedBytes);* y' _) h: x, F( N2 F
myTrace("Bytes total at progress callback=" + totalBytes);; U0 C4 N0 _: o. |3 h% _
}, k# m$ z4 U$ w6 ]
6 ~6 q7 O1 g1 W) E2 n/ r
7、我们的onLoadComplete方法仅接受一个参数,它就是容器MC实例。像onLoadStart一样,我们用getProgress方法来返回读取情况。2 J6 R* O. U9 P9 j) P9 L% f2 g4 h. ^
myMCL.onLoadComplete = function (targetMC)
/ S; ^5 \, C5 c$ V{# j9 |7 M) W; e: V; }; t
var loadProgress = myMCL.getProgress(targetMC);
0 o0 [4 q, t; H4 c- o# ~: v( ~myTrace (targetMC + " has finished loading.");& h. R, i% U, |+ p
myTrace("Bytes loaded at end=" + loadProgress.bytesLoaded);$ X/ ]( Y! ~) `4 Q- G, X
myTrace("Bytes total at end=" + loadProgress.bytesTotal);6 u$ F: e3 `& ?
}8 O# m! P* w* G) z/ D
& ?. i( r8 Z, o
8、onLoadInit方法将在所有加载的内容被下载到本地容器MC中之后才开始执行。这将使得你能更好的控制加载进来的内容的属性。我选择的图片非常大,这样我们可以把读取过程看得更加清晰,而我也要对已经加载的图片尺寸进行修整,让它能全部显示出来。
9 s) c  N: q  f* K! b& k% {myMCL.onLoadInit = function (targetMC)
) B+ K- M$ K3 n& d7 s{
9 z: U+ D/ L6 j6 }myTrace ("Movie clip:" + targetMC + " is now initialized");
! s8 a" _# d( \7 M. RtargetMC._width = 170;8 j: X+ G6 F- C1 B+ {+ a
targetMC._height = 170;  l. S" G3 k2 A  o- Q" b
}
: c+ g2 h) \) x& O% R/ @7 D
" J( N7 v5 w' B4 B9、还有一个回调方法onLoadError。如果有错误发生,它将会被触发。作为一个优秀的程序员,部署完善的应用程序的时候,对错误发生的避免措施是必不可少的!4 @1 t) A" A0 B* {
myMCL.onLoadError = function (targetMC, errorCode)
: j8 `7 B/ P7 Y% z+ W6 z{+ N6 s/ P; v  H+ G+ n
myTrace ("ERRORCODE:" + errorCode);
; ]; A8 [% [- j/ n4 E' d7 k7 x4 vmyTrace (targetMC + "Failed to load its content");6 ~3 {  H! h( U: y( X5 K( c
}
0 D/ C5 c& F" D4 h/ F* E( r, T# i7 m' A1 s+ Z3 v8 C/ e# w) ~* F1 I
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.
' r+ ~$ p( j( S1 c/ u10、我们终于将最复杂的工作部署好了。接下来我们只用使用loadClip方法读入我们需要的内容就行了。loadClip方法的两个参数分别是外埠资源的地址和容器MC的实例。# m! e) p, E# E$ P7 v& h
myMCL.loadClip("http://www.yourdomain.com/test1.swf","_root.myMC1");$ Z5 b3 ^) y( l$ T
myMCL.loadClip("http://www.yourdomain.com/test2.swf ", "_root.myMC2");; t9 F/ u! f' |0 `8 l" o0 s
myMCL.loadClip("http://www.yourdomain.com/pic.jpg", "_level0.myMC3");
2 q5 {1 m# a! ~9 x" o5 p/ I  k3 D; X% K7 O
路径可以选择相对路径。注意,路径的相对性也是一个大问题,当SWF在非本路径的HTML中被引用的时候,遵从HTML所在的路径!这一点是很多Flash教程都忽视的。所以,有时候绝对路径也有绝对路径的好处。[路径问题源文件下载,下载了就一目了然了]
+ x. N0 M0 U/ B' H! U3 V" v# K; Z4 B" u% x6 q
所有的调试工作最好在浏览器中,而非IDE中完成。而且脚本输出方式必须是AS2。
: y) H; P* F# C1 J, ^+ @/ SRemember, 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.
* y# L5 ^/ I% \. d. c& e+ d2 U" D
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 MovieClips dynamically.
1 r, n8 g8 V  U( E' ?7 W$ b' [  I5 n接下来,我将介绍实时调用MCL的情况。为了能适应更多的应用,我们经常动态地为MCL制定工作。
% f, \: Z0 ~; u' s$ D! {6 A4 c6 n$ ~) _. p  E
aw画外音:有时候,我们如此写:
" m, O; r6 a+ i) g1、var mcl:MovieClipLoader = new MovieClipLoader ();$ V2 V0 w+ g: c. w: V8 ~' Q$ ~
2、var mcl = new MovieClipLoader ();
7 l) I+ B' B. ]' K! P+ y发现第一种写法无法为MCL制定onLoadStart等事件方法。这是编译器根据指定变量的数据类型产生的问题。osflash的一些朋友给了一些有用的观点,我也发现这个问题正好涉及到Flash内部的事件响应机制,不妨介绍一下:
  ^/ O7 N1 g5 m5 bFlash的三种事件响应机制
. V9 y& B) [5 N8 j8 i+ m=====
/ s! N0 v8 v. {' {; h9 R: ?1、简单的回调函数,最老的;
, I4 ^( F% u& I  g( l9 ~& W' j, l2、侦听器,ASBroadcaster,FlashMX时代;& T8 m' n7 `9 p
3、事件侦听器,EventDispather,FlashMX2004时代
/ [/ u$ Y) O. h  W& s2 X6 `- [# V0 z
这里,MCL用的是第二种机制,而整套V2组件则使用最后一套机制。
$ G, h% ?. k& u, b2 k附:MCL官方申明,注意:上述方法中,仅包含getProgress方法!6 Z" P& q' Y  E9 h8 e
intrinsic class MovieClipLoader1 D: x6 o, A% @1 u8 t; X9 H
{( n  I/ I7 Z+ g
  function MovieClipLoader();) b9 l# Y! K: m: E. k5 B* |. A4 j

8 M' u2 Z0 [8 Z# R/ f6 B  function addListener(listener:object):Boolean;
" V8 S9 R( t7 m, k) _8 g  function getProgress(target:object):object;
  c" B, k! N% k2 e4 T1 {" [  function loadClip(url:String, target:object):Boolean;* G2 x  t, `, p
  function removeListener(listener:object):Boolean;
5 g7 Z5 x+ s1 k5 v9 M3 `  function unloadClip(target:object):Boolean;
0 K, r) ]- ~" g( {5 L2 r) x- a1 D( u+ t}( C4 G* Y2 `) H% e
个人补充认为,1、2在不严格要求数据类型的时候可以通用。
* l0 b) ]) w1 z; d# Q& r. ]% G5 J7 |
下面开始介绍用侦听器来检测MCL事件的方法。在此之前,我们解决一个最常见的问题,我们经常会在论坛中看到有人这样提问:
4 g5 P1 G7 i! d1 M- ^) [引用
1 ~# F& X4 n( n大家好,我动态地建立了一些MC,并逐个分配给它们一个事件句柄(标志)。然后,我将外埠资源读取到它们之中。但是这些分配好的事件句柄都不工作了!
) O2 A1 g1 R0 C: g4 V& `1 F* E紧接着,发问人一般会贴出一对乱七八糟的代码,并大呼救命。4 O, H. b& q' [

9 _$ I/ D. u, ~6 y; D  Z那么,我们首先来分析一下这个错误发生的原因:当外埠资源被载入到一个MC中时,这个MC将会重新初始化。这意味着任何被预先制定好的代码都将付之东流。对于开发人员已经手动在舞台上安排好的MC则并没有相关的麻烦,这是因为任何直接通过onClipEvent制定到MC的代码都能幸免被重新初始化。而动态建立的MC则进行上述的“初始化”,因为我们是在运行中给它们配置的事件代码。
( r; g# e, ~4 m+ l  q0 `
+ y5 o8 Z" r1 J9 J5 ^, r& ?' K* v( q! }我们如何避免这个问题呢?其实方法太多了,很多论坛也进行了极为详细的讨论,我就不多赘述了。# o3 @5 j+ G* A% V/ f

$ T8 F9 l5 u9 L& r. }你现在也许还记得刚才我介绍的“读取外埠数据参与Flash应用程序部署是一件非常重要和常见的工作,尤其是我们常常需要检测这些数据加载的进度”  C7 F, y3 L( Q& n9 Z  T
9 n/ T/ M& e6 c8 |) M9 r
我们已经介绍了MCL的几个回调函数,所以这里也不再赘述了。我们现在制作这样一个效果:缩略图标式的图片浏览系统。我们将要从外部读取一些JPG图片,将它们放入我们动态部署的MC中。并且我们希望这些动态建立的MC都具有各自的onPress事件。我们通过在MC装载好外部资源之后再为之分配事件。; O) z4 \+ n* F" M$ X& q/ G

3 n7 C* f3 X" C& M2 ]在我们开始之前,我还想提醒大家注意一些经常出现的疏漏:一定要在发布的时候设置成Flash7+AS2以上的版本;其次,用浏览器测试你的效果,而不是IDE;否则你将会得到奇怪的结果。
+ U5 Y- N( M! a/ [
: \4 L9 S- n! G7 T  I. f$ J: E现在,我们开始编制代码,你会发现它比你想象的要简单得多。: i. C. @5 K  b, O9 }

0 J3 Z5 G* H0 m" l/ b1、新建一个Flash文档。
1 @! C) e/ ?+ p3 k6 t% E+ M4 A
4 O0 c2 @# _5 g4 b; [7 K" o4 I2、找四张100*100像素的缩略图片。
* \- Z7 A. Z% G. k0 e. |6 O( |5 ~- l+ V% B; [. W* h
3、建立一个动态文本框,大概在300*300像素左右,使用12号字体,并使之现实边框,这样我们更好监测。别忘了设置它为多行的。
6 U, z7 [7 N$ ^5 m/ _) d( Q- P' W! F! O/ F  O
4、建立一个100X100像素的矩形,转变为MC,然后将它移出场景。这时候,他已经出现在库中了。在库中,设置他的链接名为“img”,并使其“在第一帧导出”。其实这个矩形会在外部资源载入的时候被取代,现在只是为了调试方便。4 G/ p/ D/ y2 @( J) Y5 ~; ~

% ~% s: E) m+ R; H) ~, H5、在刚才放置textBox文本框的层之上新建一层,这一层用于放置我们的代码,先写上& a8 K1 i4 z/ u/ w! n
stop();
% X$ i1 h7 K+ k/ I$ }
4 Q3 {* J& @5 \* F6、现在我们定义一个MCL的实例,此外定义一个基本对象,作为我们的侦听器:
3 L+ h; K  i# x  s( G9 m% imyMCL = new MovieClipLoader(); //define MovieClipLoader
  B1 w& W$ @5 G8 v% b  q; v( x) x4 ImyListener = new Object(); //define listener# I+ _0 _; |  I
& w  A: C) m# U& g3 A1 M) W
7、接下来我们用侦听器来侦听onLoadComplete事件,该事件的作用上文已经提到了。我们现在把它交给listener对象,而不是MCL实例。当然,最终要把侦听器对象再交回MCL(以侦听其回调函数)的时候,得到的效果就是我们需要的效果了。
" F$ w7 _6 `3 l- Z1 q) y. ]! j" m% q
记住,只有当读取完毕的时候,对MC部署事件任务才是安全可靠的!所以,在onLoadComplete被触发的时候才部署这个onPress事件给MC:
! p9 i3 J7 n3 W, KmyListener.onLoadComplete = function(targetMC){$ V! P/ q: Y, n+ W
debug.text += "LOADING OF " + targetMC& B5 ]  u6 Z! u0 f) K+ f
+ " COMPLETE" + newline;4 H4 @1 c4 A) K  [1 z# X; I
targetMC.onPress = function() {
0 o4 }( O% [9 t7 R: H0 jdebug.text += newline3 \" a( \; {. v6 M# l
+ "targetMC = " + targetMC._name;
9 g9 ~- i# j; V! H* \  U% o4 m8 @}, R) ^' m) \- A3 \' `
}
) x6 K7 y# f+ M" v5 k9 a1 c+ x1 T, I- Q% U4 H5 y
注:上述代码中有几行被人为打断,但这并不影响效果。- H# P: P& v( u1 }+ C

9 d& R; I& l, Z9 F, P& e$ B( s你也许已经注意到了,MC的实例名称在onLoadComplete被触发的时候是作为一个参数的身份传递给onLoadComplete的,这样我们控制这个MC就非常方便了。比如这里就可以用点击MC来检测事件是否被成功部署给MC。
. s8 @7 y. b" s1 U( k; m" O8 ^
( N$ x' i( G/ g/ ^1 V6 R) V8、现在我们建立一个函数,它包含一个简单的循环来部署场景上的MC。并且及时地为每一个部署好的MC分配读取外埠资源的任务(loadClip方法),代码如下:8 D- j( c2 e# M1 T) h1 S' c9 l* s
function initClips(){1 \1 n5 v/ F, I# ~
for (i=1; i<=4; i++){
1 y1 d  M* p9 P0 r# ~this.attachMovie("img", "img" + i, i);
; i) o) _* K% k& H8 s. W4 Z  R6 kthis["img"+i]._x = i*110;
: V9 u1 l2 I3 f) w; y2 w5 `0 E5 wmyMCL.loadClip("0" + i + ".jpg" ,8 K0 M4 d" D! X$ f, }1 ~" U. ^
this["img"+i]); //code wrapped, q) {' n1 D! r8 D) p/ L: s
}
8 O! Q) e1 |1 G: W; F( n}& ~/ d/ G: l. Y2 W! P: x3 p

- q, T' c; o  T1 \8 D% k8 k9、到这里基本上就完成了。现在我们剩下的工作就是注册侦听器并且按照需求调用相关函数、方法,反映到代码上就是以下两行:, e  v1 x$ J& u
myMCL.addListener(myListener);! b4 N& h5 l- _/ x
initClips();
: @. n$ x, g6 n1 @" M/ e' |
2 Y# Y2 q: T4 x, V  d注意这里的顺序,我们的侦听器对象在调用initClip()函数之前就被作用于MCL实例了。现在我们的MC的onPress事件可以顺利工作了,因为当图片被完全读入之后,事件才被分配过去。我们的代码也非常简洁。我们再也不用为了loading而去制作麻烦的循环了,MovieClipLoader帮我们完成了所有工作!6 q5 g# s+ i) {0 `' \
: w& B1 S( x% Z( B
附:完整代码如下:; [. g2 K% c, j
stop();
8 m) @; ?: x6 F% Z* B  o% TmyMCL = new MovieClipLoader();
) L3 B: d$ b' ^) F# FmyListener = new Object();
8 B, P, G  k# {6 u# Z4 zmyListener.onLoadComplete = function(targetMC)
% R5 o: b' x; A{
; V4 V8 d; P" m0 {$ X  targetMC.onPress = function ()0 V, s2 i- m0 m7 u, a7 S
  {: Y) b+ t% i$ u8 n
    trace("pressed");
  P+ G" A: c& J, d. x8 }# A  }
3 g# @4 \4 T. m. u  h}
8 L% \) D4 _/ L- U- }# u$ F- A7 w* e& I' i7 F& Y; h  h! |
function initClips()- l* F) {+ l; ~% ?# j( }; Z8 [
{9 N  u" z( r9 |% `
  for (i=1;i<=4;i++), E* L3 k5 E' w3 o3 V; `0 ^$ f
  {8 \5 {$ ]1 Q( \3 y8 q
    this.attachMovie("img","img"+i,i);
% V; V3 [3 x9 t* c" t, S" d    this["img"+i]._x = i*110;
. t4 D7 O& ~! S; ~' G; s( n    myMCL.loadClip(url,this["img"+i]);0 o: p/ P/ [, S
  }
! i  o, Z. T! ~; ^) G, }}
; l2 S# o4 E, HmyMCL.addListener(myListener);
4 b1 P6 o, [( L5 I- S+ x2 xinitClips();
. j7 ?8 s4 O! q& p2 J& M; F) f3 [4 s$ a6 [$ |" |2 _
到此为止,你应该相信MCL确实是一个不可多得的好东西了吧?:)
& X/ P' g, n. X' y& y# x) y' q# q
* f7 P4 V& G/ X% ^. _. b1 c! Q7 [" p" I4 f- H
====
$ l5 m9 D' Z# L& X, Y' Z3 F6 {1 y+ p

5 w/ k9 S* k: t2 o# b2 L+ B) G8 {三、含有v2组件相关的问题$ h4 k& Y  ^$ N  h: z6 C
9 T( s4 M  n# S0 ?( x; p. Z1 L6 X
V2,也爱,也恨!这里介绍关于含有V2组件项目的loading问题
: [' v& O  Y: A( ]转载请注明原帖:http://www.awflasher.com/blog/?id=468
$ h( W$ ]: S- h& n8 |& j0 Q, [' o2 M2 D+ O2 {
V2组件自面世以来就颇受争议,大体概括如下:
% C5 _6 k3 [  q$ i6 Y& Z2 }0 V  x9 B2 j7 }
优点:  U. L+ ^# T) p1 u
·界面比V1组件更加美观、统一,人机交互模式更加完善
1 H  R) L7 e) j( S' ~9 i( I+ h9 N·均采用面向对象脚本部署
; Y- X/ m# F/ X+ o  i7 v
; ~  {9 C. [/ y6 b& R) o) m缺点
$ w" \0 J$ |9 R2 i·体积笨重,开发一些只用到一两个组件的小应用程序时很尴尬. ^0 @% F: N9 x& k/ v

9 t+ g, x& P3 {" O" l; k* b消息机制方面使用EventDispather的消息广播机制,取代原有的AsBroadcast机制。使得刚出来的时候很多人根本不会用。
- J0 z6 \& @# {6 f" L1 \+ S
/ _2 t9 s0 [$ s" x' N' m这里就不讨论更多了,先说loading。含有大量v2组件的产品要想见人肯定是不能不作loading的,比如aw's blog左边的那个blog小贴士。然而每次在loading的时候似乎都会遇到麻烦。那就是笨重的体积全部被放到第一帧导出了,这样导致对一些300k以内的,含有v2组件的SWF文件进行远程载入的loading效果变得捉襟见肘。
; l3 h$ C6 B& B: \$ d) o) \1 l% O. _( ^* Z  s
解决的办法也不是没有,简单概括为三个步骤:6 k- o. W+ O$ T- L1 s& X
$ u* ]+ b' e" g6 n
一、去掉“Export in first frame”
$ s$ i7 ^# Q/ h/ x4 q* R9 Ghttp://www.awflasher.com/blog/attachments/200603/24_153106_v2linkage.gif: _1 m4 O( E& E* [) O7 g% N

$ c; Z' L% _3 E# G2 C  f: A8 T
; D! G* O+ o2 @4 Q- R3 \  D二、在发布的时候设置一下“Export frame for classes”,这一点非常重要!3 z! N7 Y2 @% O: C. n8 t
http://www.awflasher.com/blog/attachments/200603/24_153056_v2exporter.gif' r1 n* E( G4 P$ n

' }. w0 r8 j6 J6 w2 U
4 q* c7 f/ J$ ^三、对于外埠读取的含有V2的swf文件,将容器mc进行如下设置:. ~! R. q# D$ f- x  q
loader_mc._lockroot = true;
4 d* D6 E+ }+ K2 p- L
% K3 p( q* E& |0 S- h; u/ L好了,现在放心享受精彩而笨重的V2组件吧~!7 ~8 ?/ y6 ~9 k. q7 R" R, M
- @: i7 k9 b8 N# e' ?
本系列文章:  {9 G2 M; R- q! `+ F6 |
1 - [技术]原创-完美的loading-完美到底[基础]. D5 `+ S. r" Q- X. B
http://www.awflasher.com/blog/article.asp?id=444
: p- k) u- z, Z结合原理介绍loading基础。9 g' R- B5 ^1 ~8 h# f5 T3 Z7 R

* u: v+ r3 W4 G' u  t2 - [技术]原创-完美的loading-完美到底[利器]
  e2 ^' ]7 y0 F; `" ihttp://www.awflasher.com/blog/article.asp?id=468
/ h6 h0 z( p" p: g- D" t# i详细介绍MovieClipLoader类的使用,以及一些原理。
' W( c& ~- I( `. _3 D
. E* t7 U& U/ c* f$ v. p6 i3 - [技术]原创-完美的loading-完美到底[减负]7 L9 m/ N2 T$ \* k$ g* V
http://www.awflasher.com/blog/article.asp?id=470
4 g$ K- T. f7 V主要解决v2组件相关的loading,原文附图,至此,系列教程结束,应该不会再有loading的麻烦了!:)

TOP

不错啊

TOP

不错

TOP

发新话题