Flex で別 SWF のシンボルをロードする方法あれこれ

色々ハマってググッてもあんまり情報がなかったから調べたことを書いとく。

はじめに

Flex でスキンを変更する方法はいくつかある。とりあえず Adobe さんのサイトはこんなかんじ。
http://livedocs.adobe.com/flex/3_jp/html/help.html?content=skinning_1.html
自分はこの中でとりわけ別 SWF 内のシンボルをロードする方法について書く。
SWF のシンボルをロードする方法にも2種類あって、静的に埋め込む方法と、動的に読み込む方法がある。それぞれメリット・デメリットがあって、

メリットデメリット
静的に埋め込む方法 コンパイル時にそのシンボルについてのエラーチェックができる ・サイズが大きくなっちゃう。
・スキンの変更するときに、Flex のプロジェクトごと再コンパイルしなきゃいけない
動的に読み込む方法 ・スキンの変更するときにそのアセットSWFだけ変更すればよい
・本体のSWFのサイズは小さくなる
・エラーチェックがしにくい
・なんかいろいろハマる
こんなかんじ。とりあえず、プロジェクトの規模とかメリット・デメリットに応じて使い分ければいいんだと思う。



静的に埋め込む方法

多分こっちはいろいろメジャーなんで調べればいっぱいでてくると思う。ので、さっと解説。

読み込まれる方の SWF の作り方

Flash CS5 で作る。CS3 とか 4 とか持ってないから 5 で解説。
スキンをつくって→選択して→右クリック→シンボルに変換
リンケージでActionScript用に書き出しにチェックを入れる
1フレーム目に書き出しにチェックを入れる
クラスに読み込むための名前を入力(仮に skinTest01 と入力)
でOKして、パブリッシュする。
この SWF( skin.swf とする )を Flex プロジェクトの src/assets/skin.swf にでも配置しておく。

mxml で適応する

こんな感じのコードをかくだけ。

<mx:Button
	upSkin="@Embed('/assets/skin.swf#skinTest01')"
	/>
もしくは ActionScript で適応する

Class オブジェクトにメタデータタグで指定して、それをsetStyleするとか。

[Embed('/assets/skin.swf#skinTest01')]
private var skin:Class;

public function setStyleTest():void
{
	var button:Button = new Button();
	button.setStyle("upSkin", skin);
}

動的に読み込む方法

こっちが本題。いろいろハマる。

読み込まれる方の SWF の作り方

基本的には上のやりかたと一緒だが、それだけだと IFlexDisplayObject が実装されていなくて怒られちゃう。シンボルを作るときに、IFlexDisplayObject が実装した mx.flash.UIMovieClip を基底クラスにする必要がある。
まず、Flash CS5 のメニュー→ファイル→ActionScript設定を開く。
ライブラリパスに、FlashBuilder(FlexBuilder)のsdksのlibsにパスを通す。
Macだと、/Applications/Adobe Flash Builder 4/sdks/4.1.0/frameworks/libs)
そして、シンボルのプロパティで
リンケージのActionScript用に書き出しにチェックを入れる
1フレーム目に書き出しにチェックを入れる
クラスに読み込むための名前を入力(仮に skinTest02 と入力)
基本クラスに mx.flash.UIMovieClip を入力
でOKして、パブリッシュする。
この SWF( skin.swf とする )を Flex プロジェクトの src/assets/skin.swf にでも配置しておく。

SWF の読み込み方

Loader クラスを使って読み込む。なんか getDefinition( "クラス名" ) でクラスオブジェクトが返ってくる。

public var loader:Loader;

public function LoadTest()
{
	super();
	loader = new Loader();
	loader.contentLoaderInfo.addEventListner(Event.COMPLETE, loadCompleteHandler);
	loader.load( new URLRequest( "assets/skin.swf" ) );
}

publid function loadCompleteHandler( e:Event ):void
{
	var img:Class = loader.contentLoaderInfo.applicationDomain.getDefinition( "skinTest02" ) as Class;
	var button:Button = new Button();
	button.setStyle( "upSkin", img );
}

こんな感じ。同じドメインならセキュリティうんぬんとか抜きに考えても良さそうだけど、クロスドメインとかになるとちょっとめんどくさい感じ。そのへんは下の記事が参考になった。
Loaderの設定に関する注意点 - LoaderContext | _level0 - KAYAC Front Engineer Blog
あと、読み込まれる側の SWF は ActionScript 2 の設定でパブリッシュするとうまくいかなかった。とりあえず AS3 でパブリッシュしとくといいと思う。