2010年5月5日星期三

製作動態載入 Theme,Part 2

上一篇介紹,以 Flash IDE 製作的 swf,被當作 Flex 的素材,以 css 的方式定義,並將 css 轉成 swf 讓 Flex 應用程式動態載入,程式可透過 css 取得 Class,動態建立視覺物件。
http://blog.ben.idv.tw/2010/05/flex-flash-theme.html

這篇,少掉 Flex 的架構 (雖然我是用 Flex Builder 的 ActionScript 專案在開發),以 Flash IDE 製作的 swf 直接被當作動態載入的 Theme 資源,載入後直接由其中取出 Class,動態建立視覺物件。


首先,同樣先準備三個 FLA,結構必須相同,意思是 instance name 必須相同:







第二步驟,準備開發主程式,檔案架構如下圖所示:



與上一篇最大的不同,就在於這次因為沒有定義 css,所以不是採用 css 的方式來載入外部 Theme 資源,而是使用自定的 ThemeLoader 來載入,載入完成後的其它步驟就與上一篇相同。

ThemeDemo.as
package {
import flash.display.Sprite;
import flash.events.Event;

import ui.proxy.MC1Proxy;

import util.ThemeLoader;

[SWF(width="640", height="480")]
public class ThemeDemo extends Sprite
{
static public const Theme1Url:String = "asset/asset1.swf";
static public const Theme2Url:String = "asset/asset2.swf";
static public const Theme3Url:String = "asset/asset3.swf";

private var _mc1:Sprite;
private var _mc1proxy:MC1Proxy;

public function ThemeDemo()
{
ThemeLoader.getInstance().addEventListener(Event.CHANGE, onThemeLoader_change);

ThemeLoader.getInstance().load(ThemeDemo.Theme1Url);
}

private function onThemeLoader_change(e:Event):void{
if(_mc1!=null && _mc1.parent!=null)
_mc1.parent.removeChild(_mc1);

var Cls:Class = ThemeLoader.getInstance().getClass("ui.MC1");
if(Cls!=null){
_mc1 = new Cls() as Sprite;
this.addChild(_mc1);
}

if(_mc1proxy==null)
_mc1proxy = new MC1Proxy(_mc1);
else
_mc1proxy.updateView(_mc1);
}
}
}


MC1Proxy.as
package ui.proxy
{
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.MouseEvent;

import util.ThemeLoader;

public class MC1Proxy extends FlashUIComponentProxy
{
//child
private var _b1:SimpleButton;
private var _b2:SimpleButton;
private var _b3:SimpleButton;
private var _mcInner:Sprite;

//child proxy
private var _mcInnerProxy:MCInnerProxy;

public function MC1Proxy(view:Sprite)
{
super(view);
}

override protected function makeLink():void{
//child
_b1 = view.getChildByName("b1") as SimpleButton;
_b2 = view.getChildByName("b2") as SimpleButton;
_b3 = view.getChildByName("b3") as SimpleButton;
_mcInner = view.getChildByName("mcInner") as Sprite;

//child proxy;
if(_mcInnerProxy==null)
_mcInnerProxy = this.setChildProxy(_mcInner, MCInnerProxy) as MCInnerProxy;
else
_mcInnerProxy.updateView(_mcInner);

//child's event handler
_b1.addEventListener(MouseEvent.CLICK, onB1_click, false, 0, true);
_b2.addEventListener(MouseEvent.CLICK, onB2_click, false, 0, true);
_b3.addEventListener(MouseEvent.CLICK, onB3_click, false, 0, true);
}

private function onB1_click(e:MouseEvent):void{
_mcInnerProxy.msg = "click 1";
ThemeLoader.getInstance().load(ThemeDemo.Theme1Url);
}

private function onB2_click(e:MouseEvent):void{
_mcInnerProxy.msg = "click 2";
ThemeLoader.getInstance().load(ThemeDemo.Theme2Url);
}

private function onB3_click(e:MouseEvent):void{
_mcInnerProxy.msg = "click 3";
ThemeLoader.getInstance().load(ThemeDemo.Theme3Url);
}

}
}


MCInnerProxy.as
package ui.proxy
{
import flash.display.Sprite;
import flash.text.TextField;

public class MCInnerProxy extends FlashUIComponentProxy
{
//child
private var _txt:TextField;

//getter / setter
private var _msg:String = "";
public function get msg():String{return _msg;}
public function set msg(value:String):void{
if(_msg==value)
return;
_msg = value;
this.invalidateDisplayList();
}

public function MCInnerProxy(view:Sprite)
{
super(view);
}

override protected function makeLink():void{
//child
_txt = view.getChildByName("txt") as TextField;
}

override protected function updateDisplayList():void{
_txt.text = msg;
}

}
}


ThemeLoader.as
package util
{
import flash.events.Event;
import flash.events.EventDispatcher;

[Event(name="change", type="flash.events.Event")]
public class ThemeLoader extends EventDispatcher
{
static private var _instance:ThemeLoader;
static public function getInstance():ThemeLoader{
if(_instance==null)
_instance = new ThemeLoader;
return _instance;
}

private var _loader:ClassLoader = new ClassLoader();

public function load(url:String):void{
_loader.addEventListener(ClassLoader.CLASS_LOADED, onLoaded);
_loader.load(url);
}

private function onLoaded(e:Event):void{
this.dispatchEvent(new Event(Event.CHANGE));
}

public function getClass(className:String):Class{
if(_loader==null)
return null;
return _loader.getClass(className);
}
}
}


Demo

10 意見:

匿名 提到...

test. confidential text. thx.

匿名 提到...

版主您好,
不好意思,我有事情想向您請教,能否將意見設定為私密留言 or 能否寄問題到您的信箱?
十分感謝!

Ben Chang 提到...

如果是一般問題詢問,直接 PO 就可以了,或是在討論區 PO,也可以有更多人一起解答。

如果是業務合作,可以 mail 到我信箱 ben{dot}rb{dot}chang{at}gmail{dot}com

若想用私密留言,我想只要你有登錄 google 帳號的話,應該也可使用才是~

匿名 提到...

版主:抱歉,前幾天已經寄信到您信箱(主旨:版主,請幫忙...),今天有再寄一次,再煩請您幫個忙,感謝。請再幫忙查看信件是否跑到"垃圾郵件"處,謝謝您的幫忙。

Ben Chang 提到...

果然沒有看到,我信箱每天平均有 100 封垃圾郵件,只要過個幾天很快就會掩埋過去了,所以......很抱歉

Ben Chang 提到...

看到你的訊息了,我會去研究一下 xuite 的留言板怎麼使用,呵呵

匿名 提到...

版主,謝謝幫忙!請見回信。

Victor 提到...

你好

想請教關於Accordion組件的問題

比如我在Accordion內建置兩個設有backgroundColor的Box,每當我從第一個Box跳到第二個Box時,背景總是會先出現Accordion預設的白色背景後,才會再出現第二個Box的背景顏色,這樣轉頁的感覺很不流暢

我試過在Accordion加上creationPolicy=all,但結果還是一樣,每次都一定會先出現白色背景

請問一下這問題該如何解決?

謝謝~

Ben Chang 提到...

我測試 加上creationPolicy=all 是可以的

Victor 提到...

我後來測試creationPolicy=all 功能也是可以實現了 (看來好像是temp的關係讓我一直鬼擋牆 = =")

再請教一個問題

我想要實現一個功能是按鈕部份,click和doubleClick會分別觸發2種不同的函式,但當我doubleClick時,會連同click也一起觸發,有辨法在doubleClick時不去觸發click嗎?

謝謝~