
Flash CS4 Professional で開発を行っていると、ムービーをプレビューで確認するときは基本的に Flash Player 10 になってしまうので、Flash Player 9 用コンテンツを作っているとややその動作の差異に頭を悩ませる事はしばしばあります。
なんだかんだで Flash サイトはまだ Flash Player 9 対象が基本。Flash CS5 が出たら Flash Player 10 または 11 が基本になるんだろうか。Flash Player 11 では Dynamic Sound Generate の機能が強化されるといいなぁ。今のバッファサイズじゃレイテンシとかがちょっと悩ましい。簡単サウンド API が提供されるともっといいな。
Flash Player 9 の場合、外部からロードするコンテンツを addChild(loader) ではなく、 addChild(loader.content) するようにしておくと、removeChild(loader.content) して unload() するときにエラーが出てしまいます。
これが Flash Player 10 だったりすると、エラーは出ず正常に removeChild() と unload() が行われます。
ためしたサンプルコード。各ボタンを押した瞬間、red.swf、blue.swf、green.swf をロードしています。
red_btn.addEventListener(MouseEvent.CLICK, clickHandler);
blue_btn.addEventListener(MouseEvent.CLICK, clickHandler);
green_btn.addEventListener(MouseEvent.CLICK, clickHandler);
//ロードされるコンテンツのコンテナー
var container:Sprite = new Sprite();
container.y = 100;
addChild(container);
//ローダー。このローダーを使い回す。
var loader:Loader;
//現在ロードしてるコンテンツ名を格納しておく。
var current:String = "";
function clickHandler(event:MouseEvent):void
{
var target:MovieClip = MovieClip(event.currentTarget);
var swfName:String = target.name.substr(0, target.name.lastIndexOf("_"));
loadContent(swfName);
}
function loadContent(swfName:String):void
{
if (current == swfName)
return;
if(loader && loader.content)
{
container.removeChild(loader.content);
loader.unload();
loader = null;
}
current = swfName;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
loader.load(new URLRequest(swfName + ".swf"));
}
function loadCompleteHandler(event:Event):void
{
var loader:Loader = LoaderInfo(event.currentTarget).loader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadCompleteHandler);
container.addChild(loader.content);
}
Loader でロードした中身(content)を親の DisplayObjectContainer に addChild し、消すときは removeChild で Loader の中身を親から取り外したあと、Loader をクリア(unload)。この瞬間に Flash Player 9 だとエラーが出ます。
ArgumentError: Error #2025: 指定した DisplayObject は呼び出し元の子でなければなりません。
at flash.display::Loader/unload()
at main_fla::MainTimeline/loadContent()[main_fla.MainTimeline::frame1:31]
at main_fla::MainTimeline/clickHandler()[main_fla.MainTimeline::frame1:20]
Flash Player 10 で同じくダメなのであれば「そういうものなのね」で自己解決できるのですが、問題なく出来てしまいますし、心持ちこちらの方が美しい気がするので悩ましい所。(MVC 的に Loader という Controller と、content という View な感じ)
これを解決するには loader.content を addChild するのではなく、 loader を addChild するかたちにして、removeChild のときも同様にすれば解決できます。
上のコードの問題を解消したサンプルコード。loader.content ではなく、loader を addChild しています。
red_btn.addEventListener(MouseEvent.CLICK, clickHandler);
blue_btn.addEventListener(MouseEvent.CLICK, clickHandler);
green_btn.addEventListener(MouseEvent.CLICK, clickHandler);
//ロードされるコンテンツのコンテナー
var container:Sprite = new Sprite();
container.y = 100;
addChild(container);
//ローダー。このローダーを使い回す。
var loader:Loader;
//現在ロードしてるコンテンツ名を格納しておく。
var current:String = "";
function clickHandler(event:MouseEvent):void
{
var target:MovieClip = MovieClip(event.currentTarget);
var swfName:String = target.name.substr(0, target.name.lastIndexOf("_"));
loadContent(swfName);
}
function loadContent(swfName:String):void
{
if (current == swfName)
return;
if(loader && loader.content)
{
container.removeChild(loader);
loader.unload();
loader = null;
}
current = swfName;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
loader.load(new URLRequest(swfName + ".swf"));
}
function loadCompleteHandler(event:Event):void
{
var loader:Loader = LoaderInfo(event.currentTarget).loader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadCompleteHandler);
container.addChild(loader);
}
addChild(loader) ってなんかすごい気持ち悪い気がするのですが、そもそも loader は DisplayObject なんだ思うと、ぐっとこらえられる気もします。
---
そういえば先月の Web Designing の「Flash の学校」で、Flash Player 10 の機能である「Dynamic Sound Generate」を使ったプライベートワークの「A Flash Polyphonic Synthesizer」がこっそり載っていました。
プライベートワークが本に載ったのは初めてです。多分。ちょっと嬉しかったです。よろしければ触ってみた事がない方は触ってみてください。デザインもインタラクションも、あまりにも適当なので、今度はそのあたり頑張ります。

