Flex4のカスタムプリローダー

Filed under AS3, Flex4



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>

Post a Comment

Your email is never published nor shared.