Flex4でのカスタムプリローダー作成の話です。
こんな感じになります。
以下、ソースコード(swfを右クリックしても見れます)と簡単な解説。
Flex3の時とちょっとだけ異なる点があります。
手探りでやってるので、間違いなどあればご指摘お願いします。
Flex4は、デフォルトでランタイム共有ライブラリ(RSL)を使うようになっています。
swfのロードと同時にRSLのロードも行います。
Flex4SDKのデフォルトでは、以下の流れでロードが実行されます。
Flex3では、「Event.COMPLETEはSWF ファイルのダウンロードが完了すると送出される」と書いてあったのですが、Flex4ではRSLとswfのロードが両方終わるまでEvent.COMPLETEは送出されてないような気が・・・(traceとかで見た限り)。
このあたり、まだよく分かっていません。。

RSLのロードを除けば、あとはFlex3と同じです。
ちなみに、Flex4ではSparkDownloadProgressBarというのがあって、これを継承するだけでもプリローダーが作れるようです(SparkDownloadProgressBarが、SpriteクラスとIPreloaderDisplayインターフェースを継承を継承している)。
プリローダーのソース。
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import mx.events.FlexEvent;
import mx.events.RSLEvent;
import mx.preloaders.IPreloaderDisplay;
import mx.preloaders.Preloader;
public class MyPreloader extends Sprite implements IPreloaderDisplay
{
private var _preloader:Preloader;
private var _loaded:int;
private var _loading:int;
private var _rsl_loaded:int;
private var _rsl_loading:int;
private var _frameType:int;
private var _count:int;
private var _isSwfComplete:Boolean;
private var _isComplete:Boolean;
private var _textField:TextField;
// ロード状況を表示するTextFieldの作成とイベントの追加
public function initialize():void
{
_textField = addChild(new TextField) as TextField;
_textField.selectable = false;
_textField.defaultTextFormat = new TextFormat(null, 16, 0x000000);
_textField.autoSize = TextFieldAutoSize.LEFT;
onResize();
_loaded = _loading = _rsl_loaded = _rsl_loading = _frameType = _count = 0;
_isComplete = _isSwfComplete = false;
addEventListener(Event.ENTER_FRAME, onFrame);
stage.addEventListener(Event.RESIZE, onResize);
}
// プリローダーにイベントを追加
public function set preloader(obj:Sprite):void
{
_preloader= Preloader(obj);
_preloader.addEventListener(ProgressEvent.PROGRESS, onProgress);
_preloader.addEventListener(RSLEvent.RSL_COMPLETE, onRslComplete);
_preloader.addEventListener(Event.COMPLETE, onSwfComplete);
_preloader.addEventListener(FlexEvent.INIT_COMPLETE, onComplete);
}
// swfのロード状況を更新
private function onProgress(e:ProgressEvent):void
{
_loaded = (e.bytesLoaded / e.bytesTotal ) * 100;
}
// swfのロードが終了したら通知
private function onSwfComplete(e:Event):void
{
_isSwfComplete = true;
}
// RSLのロード状況を更新
private function onRslComplete(e:RSLEvent):void
{
_rsl_loaded = 100*(e.rslIndex+1)/e.rslTotal;
}
// 全ロード&初期化が終了したら通知
private function onComplete(e:Event):void
{
_isComplete = true;
}
// リサイズイベント
private function onResize(e:Event=null):void
{
_textField.x = (stage.stageWidth - 100) *0.5;
_textField.y = (stage.stageHeight - 5)*0.5;
}
// フレームイベント。各ロード状況に応じて、情報をTextFieldに表示する。
private function onFrame(e:Event):void
{
switch(_frameType)
{
// swf&rslのロード状況を表示する
case 0:
if(_loaded > _loading) _loading ++;
if(_rsl_loaded > _rsl_loading) _rsl_loading ++;
_textField.text = "Now loading : " + _loading.toString() + "%.\nNow RSL Loading : " + _rsl_loading.toString() + "%.";
if(_loaded == _loading && _rsl_loaded == _rsl_loading && _isSwfComplete && _loaded != 0 && _rsl_loaded != 0)
{
_textField.text = "Now Initializing.";
_frameType = 1;
}
break;
// 初期化を待つ
case 1:
if(_isComplete) _frameType = 2;
_textField.text = "Load Complete !";
break;
// 全ロード & 初期化が終わったらプリローダーを終了
case 2:
_count ++;
if(_count > 20)
{
removeEventListener(Event.ENTER_FRAME, onFrame);
stage.removeEventListener(Event.RESIZE, onResize);
_preloader.removeEventListener(ProgressEvent.PROGRESS, onProgress);
_preloader.removeEventListener(RSLEvent.RSL_COMPLETE, onRslComplete);
_preloader.removeEventListener(Event.COMPLETE, onSwfComplete);
_preloader.removeEventListener(FlexEvent.INIT_COMPLETE, onComplete);
removeChild(_textField);
// Flex側へ画面を移行
dispatchEvent(new Event(Event.COMPLETE));
}
break;
}
}
// 以下、コンストラクタ & ゲッター & セッター
public function MyPreloader(){super();}
public function get backgroundAlpha():Number{return 0;}
public function set backgroundAlpha(value:Number):void{}
public function get backgroundColor():uint{return 0;}
public function set backgroundColor(value:uint):void{}
public function get backgroundImage():Object{return null;}
public function set backgroundImage(value:Object):void{}
public function get backgroundSize():String{return null;}
public function set backgroundSize(value:String):void{}
public function get stageHeight():Number{return 0;}
public function set stageHeight(value:Number):void{}
public function get stageWidth():Number{return 0;}
public function set stageWidth(value:Number):void{}
}
}
Flex側のソース。
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
applicationComplete="{effect.play();}"
preloader="MyPreloader" viewSourceURL="srcview/index.html">
<!-- カンバスを表示 -->
<mx:Canvas id="myCanvas" width="0" height="0" alpha="0" borderColor="0x000000" borderStyle="solid" horizontalCenter="0" verticalCenter="0">
<mx:Text text="complete" horizontalCenter="0" verticalCenter="0" />
</mx:Canvas>
<!-- キャンバスを表示させるエフェクト -->
<fx:Declarations>
<s:Sequence id="effect" target="{myCanvas}" duration="400">
<s:Animate>
<s:SimpleMotionPath property="height" valueFrom="0" valueTo="100"/>
<s:SimpleMotionPath property="alpha" valueFrom="0" valueTo="1" />
<s:SimpleMotionPath property="width" valueFrom="0" valueTo="10" />
</s:Animate>
<s:Animate>
<s:SimpleMotionPath property="width" valueFrom="10" valueTo="300" />
</s:Animate>
</s:Sequence>
</fx:Declarations>
</s:Application>
