完美的loading-吐血整理!

來源:互聯網
上載者:User
共三部分:
1、基礎
2、MovieClipLoader相關討論(較深入)
3、V2組件相關問題

一、基礎
很久沒有發技術日誌了,要來就來個完美的。您別激動,一個小小的loading談什麼完美,我想你看了就知道^_^
我的口號,將此文打造成全球最完善的非Flash初學者loading教程貼。
轉載請保留原文地址:http://www.awflasher.com/blog/?id=444

首先,想說一下我寫此文的動機。記得很早之前我曾經說過“沒有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

================================

二、MovieClipLoader類說明

參考英文教程,並作出大量原創補充 - Neil Webb, neil AT nwebb DOT co DOT uk, http://www.nwebb.co.uk
轉載請註明原帖:http://www.awflasher.com/blog/?id=468

讀取外埠資料參與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 MovieClips dynamically.
接下來,我將介紹即時調用MCL的情況。為了能適應更多的應用,我們經常動態地為MCL制定工作。

aw畫外音:有時候,我們如此寫:
1、var mcl:MovieClipLoader = new MovieClipLoader ();
2、var mcl = new MovieClipLoader ();
發現第一種寫法無法為MCL制定onLoadStart等事件方法。這是編譯器根據指定變數的資料類型產生的問題。osflash的一些朋友給了一些有用的觀點,我也發現這個問題正好涉及到Flash內部的事件響應機制,不妨介紹一下:
Flash的三種事件響應機制
=====
1、簡單的回呼函數,最老的;
2、接聽程式,ASBroadcaster,FlashMX時代;
3、事件接聽程式,EventDispather,FlashMX2004時代

這裡,MCL用的是第二種機制,而整套V2組件則使用最後一套機制。
附:MCL官方申明,注意:上述方法中,僅包含getProgress方法!
intrinsic class MovieClipLoader
{
  function MovieClipLoader();

  function addListener(listener:object):Boolean;
  function getProgress(target:object):object;
  function loadClip(url:String, target:object):Boolean;
  function removeListener(listener:object):Boolean;
  function unloadClip(target:object):Boolean;
}
個人補充認為,1、2在不嚴格要求資料類型的時候可以通用。

下面開始介紹用接聽程式來檢測MCL事件的方法。在此之前,我們解決一個最常見的問題,我們經常會在論壇中看到有人這樣提問:
引用
大家好,我動態地建立了一些MC,並逐個分配給它們一個事件控制代碼(標誌)。然後,我將外埠資源讀取到它們之中。但是這些分配好的事件控制代碼都不工作了!
緊接著,發問人一般會貼出一對亂七八糟的代碼,並大呼救命。

那麼,我們首先來分析一下這個錯誤發生的原因:當外埠資源被載入到一個MC中時,這個MC將會重新初始化。這意味著任何被預先制定好的代碼都將付之東流。對於開發人員已經手動在舞台上安排好的MC則並沒有相關的麻煩,這是因為任何直接通過onClipEvent制定到MC的代碼都能倖免被重新初始化。而動態建立的MC則進行上述的“初始化”,因為我們是在運行中給它們配置的事件代碼。

我們如何避免這個問題呢?其實方法太多了,很多論壇也進行了極為詳細的討論,我就不多贅述了。

你現在也許還記得剛才我介紹的“讀取外埠資料參與Flash應用程式部署是一件非常重要和常見的工作,尤其是我們常常需要檢測這些資料載入的進度”

我們已經介紹了MCL的幾個回呼函數,所以這裡也不再贅述了。我們現在製作這樣一個效果:縮圖標式的圖片瀏覽系統。我們將要從外部讀取一些JPG圖片,將它們放入我們動態部署的MC中。並且我們希望這些動態建立的MC都具有各自的onPress事件。我們通過在MC裝載好外部資源之後再為之分配事件。

在我們開始之前,我還想提醒大家注意一些經常出現的疏漏:一定要在發布的時候設定成Flash7+AS2以上的版本;其次,用瀏覽器測試你的效果,而不是IDE;否則你將會得到奇怪的結果。

現在,我們開始編製代碼,你會發現它比你想象的要簡單得多。

1、建立一個Flash文檔。

2、找四張100*100像素的縮圖片。

3、建立一個動態文字框,大概在300*300像素左右,使用12號字型,並使之現實邊框,這樣我們更好監測。別忘了設定它為多行的。

4、建立一個100X100像素的矩形,轉變為MC,然後將它移出情境。這時候,他已經出現在庫中了。在庫中,設定他的連結名為“img”,並使其“在第一幀匯出”。其實這個矩形會在外部資源載入的時候被取代,現在只是為了調試方便。

5、在剛才放置textBox文字框的層之上建立一層,這一層用於放置我們的代碼,先寫上
stop();

6、現在我們定義一個MCL的執行個體,此外定義一個基本對象,作為我們的接聽程式:
myMCL = new MovieClipLoader(); //define MovieClipLoader
myListener = new Object(); //define listener

7、接下來我們用接聽程式來偵聽onLoadComplete事件,該事件的作用上文已經提到了。我們現在把它交給listener對象,而不是MCL執行個體。當然,最終要把接聽程式對象再交回MCL(以偵聽其回呼函數)的時候,得到的效果就是我們需要的效果了。

記住,只有當讀取完畢的時候,對MC部署事件任務才是安全可靠的!所以,在onLoadComplete被觸發的時候才部署這個onPress事件給MC:
myListener.onLoadComplete = function(targetMC){
debug.text += "LOADING OF " + targetMC
+ " COMPLETE" + newline;
targetMC.onPress = function() {
debug.text += newline
+ "targetMC = " + targetMC._name;
}
}

註:上述代碼中有幾行被人為打斷,但這並不影響效果。

你也許已經注意到了,MC的執行個體名稱在onLoadComplete被觸發的時候是作為一個參數的身份傳遞給onLoadComplete的,這樣我們控制這個MC就非常方便了。比如這裡就可以用點擊MC來檢測事件是否被成功部署給MC。

8、現在我們建立一個函數,它包含一個簡單的迴圈來部署情境上的MC。並且及時地為每一個部署好的MC分配讀取外埠資源的任務(loadClip方法),代碼如下:
function initClips(){
for (i=1; i<=4; i++){
this.attachMovie("img", "img" + i, i);
this["img"+i]._x = i*110;
myMCL.loadClip("0" + i + ".jpg" ,
this["img"+i]); //code wrapped
}
}

9、到這裡基本上就完成了。現在我們剩下的工作就是註冊接聽程式並且按照需求調用相關函數、方法,反映到代碼上就是以下兩行:
myMCL.addListener(myListener);
initClips();

注意這裡的順序,我們的接聽程式對象在調用initClip()函數之前就被作用於MCL執行個體了。現在我們的MC的onPress事件可以順利工作了,因為當圖片被完全讀入之後,事件才被分配過去。我們的代碼也非常簡潔。我們再也不用為了loading而去製作麻煩的迴圈了,MovieClipLoader幫我們完成了所有工作!

附:完整代碼如下:
stop();
myMCL = new MovieClipLoader();
myListener = new Object();
myListener.onLoadComplete = function(targetMC)
{
  targetMC.onPress = function ()
  {
    trace("pressed");
  }
}

function initClips()
{
  for (i=1;i<=4;i++)
  {
    this.attachMovie("img","img"+i,i);
    this["img"+i]._x = i*110;
    myMCL.loadClip(url,this["img"+i]);
  }
}
myMCL.addListener(myListener);
initClips();

到此為止,你應該相信MCL確實是一個不可多得的好東西了吧?:)

====

三、含有v2組件相關的問題

V2,也愛,也恨!這裡介紹關於含有V2組件項目的loading問題
轉載請註明原帖:http://www.awflasher.com/blog/?id=468

V2組件自面世以來就頗受爭議,大體概括如下:

優點:
·介面比V1組件更加美觀、統一,人機互動模式更加完善
·均採用物件導向指令碼部署

缺點
·體積笨重,開發一些只用到一兩個組件的小應用程式時很尷尬

訊息機制方面使用EventDispather的訊息廣播機制,取代原有的AsBroadcast機制。使得剛出來的時候很多人根本不會用。

這裡就不討論更多了,先說loading。含有大量v2組件的產品要想見人肯定是不能不作loading的,比如aw's blog左邊的那個blog小貼士。然而每次在loading的時候似乎都會遇到麻煩。那就是笨重的體積全部被放到第一幀匯出了,這樣導致對一些300k以內的,含有v2組件的SWF檔案進行遠程載入的loading效果變得捉襟見肘。

解決的辦法也不是沒有,簡單概括為三個步驟:

一、去掉“Export in first frame”
http://www.awflasher.com/blog/attachments/200603/24_153106_v2linkage.gif

二、在發布的時候設定一下“Export frame for classes”,這一點非常重要!
http://www.awflasher.com/blog/attachments/200603/24_153056_v2exporter.gif

三、對於外埠讀取的含有V2的swf檔案,將容器mc進行如下設定:
loader_mc._lockroot = true;

好了,現在放心享受精彩而笨重的V2組件吧~!

本系列文章:
1 - [技術]原創-完美的loading-完美到底[基礎]
http://www.awflasher.com/blog/article.asp?id=444
結合原理介紹loading基礎。

2 - [技術]原創-完美的loading-完美到底[利器]
http://www.awflasher.com/blog/article.asp?id=468
詳細介紹MovieClipLoader類的使用,以及一些原理。

3 - [技術]原創-完美的loading-完美到底[減負]
http://www.awflasher.com/blog/article.asp?id=470
主要解決v2組件相關的loading,原文附圖,至此,系列教程結束,應該不會再有loading的麻煩了!:)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.