這裡指的 "換掉部分元素",是在不變更設計、或不影響原程式座標邏輯之下,改變顏色、風格的需求。
作法一,將整份 FLA 複製一份,改完 UI 設計,輸出!
優:最快
缺:每份 FLA 都有程式邏輯,每次異動,都要重新發佈所有 FLA
作法二,調整一些程式,動態載入要更換的元素,放在與原設計相同的座標、縮放、旋轉角度、層級中。
優:邏輯只有一份,不同的 UI 可被動態載入
缺:有一堆苦工要作,可大可小
這裡不討論 Flex / MXML 的作法,畢竟木已成舟,誰叫我們以前都喜歡用 FLA 呢!
以下,我說明 作法二 我會怎麼作:
1.
假設 FLA 中的視覺如下,畫面中有 logo、bg、與其他一堆東西:

logo 是右上角的圓圈
bg 是整個畫面的框架
其他東西 就是那些各方框中的圓形按鈕

輸出畫面就不用看了,就跟上面的設計畫面一樣~
接下來,就是要儘量調整最少的程式,來作到將 logo、bg 由外部載入!
2.
將希望由外部載入的元素,變成 Class,如果原本就已經是 Class 也沒關係,譬如以下我將 logo 與 bg 連結到 CustResLogo 與 CustResBG 兩個 Class 上:

CustResLogo.as
package
{
import flash.display.MovieClip;
public class CustResLogo extends MovieClip
{
public function CustResLogo()
{
CustomizeResourceController.getInstance().registerView("CustResLogo", onResLoaded);
}
private function onResLoaded(Cls:Class):void{
//clear
while(numChildren>0)
removeChildAt(0);
graphics.clear();
//create
var mc:MovieClip = new Cls() as MovieClip;
addChild(mc);
}
}
}
CustResBG.as
package
{
import flash.display.MovieClip;
public class CustResBG extends MovieClip
{
public function CustResBG()
{
CustomizeResourceController.getInstance().registerView("CustResBG", onResLoaded);
}
private function onResLoaded(Cls:Class):void{
//clear
while(numChildren>0)
removeChildAt(0);
graphics.clear();
//create
var mc:MovieClip = new Cls() as MovieClip;
addChild(mc);
}
}
}
這兩個 Class 大同小異,都是向 CustomizeResourceController 註冊自己,目的是要取得外部資源 (*.swf) 中,名叫 "CustResLogo" 的 Class Name 的 Class,當取得之後(onResLoaded()被呼叫),就利用該 Class 重新建立視覺。
3.
新建 CustomizeResourceController 類別,這個類別負責載入外部 swf,並通知所有向自己註冊的 MovieClip 作更新畫面的工作:
CustomizeResourceController.as
package
{
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.system.ApplicationDomain;
public class CustomizeResourceController extends EventDispatcher
{
static private var _instance:CustomizeResourceController;
static public function getInstance():CustomizeResourceController{
if(_instance==null)
_instance = new CustomizeResourceController;
return _instance;
}
private var _isLoaded:Boolean = false;
private var _clsLdr:ClassLoader = new ClassLoader;
public function CustomizeResourceController()
{
if(_instance!=null)
throw new Error("plz use getInstance()");
_instance = this;
}
public function load(uri:String):void{
if(_isLoaded)
throw new Error("loaded"); //只 load 一次
_clsLdr.addEventListener(ClassLoader.CLASS_LOADED, onResLoaded, false, 0, true);
_clsLdr.addEventListener(IOErrorEvent.IO_ERROR, onError, false, 0, true);
_clsLdr.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError, false, 0, true);
_clsLdr.load(uri, new ApplicationDomain());
}
private function onResLoaded(e:Event):void{
_isLoaded = true;
notifyViews();
this.dispatchEvent(new Event(Event.COMPLETE));
}
private function onError(e:ErrorEvent):void{
//動作結束
this.dispatchEvent(new Event(Event.COMPLETE));
}
private var _views:Array = new Array();
public function registerView(className:String, callback:Function):void{
_views.push({className: className
, callback: callback});
if(_isLoaded)
notifyView(className, callback);
}
private function notifyViews():void{
for(var i:int=0; i<_views.length; i++){
notifyView(_views[i]["className"], _views[i]["callback"]);
}
}
private function notifyView(className:String, callback:Function):void{
var Cls:Class = _clsLdr.getClass(className);
if(callback!=null && Cls!=null)
callback(Cls);
}
}
}
4.
ClassLoader 類別,我就不轉貼了,請自己去任一版 AS3 Help 中取來用:
http://help.adobe.com/zh_TW/AS3LCR/Flash_10.0/flash/system/ApplicationDomain.html
只要注意 ApplicationDomain 的部分,因為我的範例中,放在外部 swf 中的類別名稱直接與主程式 swf 中一樣,所以我會將 ApplicationDomain 拉出來變成可以自己設定。
ClassLoader.as 部分程式碼:
public function load(lib:String, applicationDomain:ApplicationDomain=null):void {
trace(this, "load()", lib);
if(applicationDomain==null)
applicationDomain = ApplicationDomain.currentDomain;
swfLib = lib;
request = new URLRequest(swfLib);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = applicationDomain;
loader.load(request,context);
}
5.
在 Document Class 中,執行載入外部 swf 的工作,這裡我的範例是載入 resource.swf:
Main.as
package{
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip{
private const customizeResourceUri:String = "resource.swf";
public function Main(){
loadCustomizeResource();
}
private function loadCustomizeResource():void{
if(customizeResourceUri != ""){
CustomizeResourceController.getInstance().addEventListener(Event.COMPLETE, onCustomizeResourceControllerLoaded);
CustomizeResourceController.getInstance().load(customizeResourceUri);
}else{
nextAction();
}
}
private function onCustomizeResourceControllerLoaded(e:Event):void{
CustomizeResourceController.getInstance().removeEventListener(Event.COMPLETE, onCustomizeResourceControllerLoaded);
nextAction();
}
private function nextAction():void{
trace("done!!");
}
}
}
6.
最後,當然就是要製作 resource.swf 囉,只要將 main.fla 中,剛剛有設定要動態置換的 logo 與 bg 從 library 中複製到 resource.fla 中,發佈即可。
這裡要注意的是在 library 中這些元素,都是在第一影格就匯出類別,而類別名稱可以任意決定,或像我一樣用與 main.fla 中相同的類別名稱。

7.
測試,再次輸出 main.swf 執行畫面如下:

可以看到 bg 框架與 logo 都已經置換,而其他元素(那堆綠色圓形按鈕)則維持原樣。
因為是動態載入 resource.swf,然後從中取得指定的 Class Name 實體化,來改變既有的視覺 UI,所以 loading 的機制是不可少的,不然就會被網友看到畫面的改變,loading 機制在原本的專案中應已含括,這裡就不 demo 了。
0 意見:
張貼意見