[Flex] カスタムコンポーネントとASの連携、BindingUtilsとか

2010/04/27

こんにちは。きんくまです。

Photoshop Panelを利用するのにFlashCS4だとうまくいかなかったので、Flexですすめることにしました。
そしたら、いろいろと知りたいことがでてきたのでまとめです。
なので、今回はFlashIDEで普段やっているけどmxmlはさっぱり!の人向けです。

今回作ったサンプル

 

※10/04/28 メインのMXMLからスクリプト部分を外部ファイル化しました。

■リスト表示のもととなるMXML
MyListComponentView.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:List xmlns:mx="http://www.adobe.com/2006/mxml">
</mx:List>

■上のMyListComponentView.mxmlを拡張したもの
MyListComponent.as

package
{
	import mx.binding.utils.BindingUtils;
	import mx.events.FlexEvent;
	
	public class MyListComponent extends MyListComponentView
	{
		public var bookDatas:BookDatas;
		
		public function MyListComponent()
		{
			super();
			addEventListener(FlexEvent.CREATION_COMPLETE, init);
		}

		private function init(e:FlexEvent):void
		{
			bookDatas = BookDatas.instance;
			dataProvider = bookDatas.datas;
		}
		
		public function update():void
		{
			dataProvider = bookDatas.datas;
		}
	}
}

■リスト表示のための1つのデータ
BookData.as

package
{
	public class BookData
	{
		public var label:String;
		public var price:int;
		
		public function BookData(label:String, price:int)
		{
			this.label = label;
			this.price = price;
		}

	}
}

■データ格納クラス
BookDatas.as

package
{
	[Bindable]
	public class BookDatas
	{ 
		private static var _instance:BookDatas;
		private var _datas:Array;
		public function get datas():Array
		{
			return _datas;
		}
		
		public function BookDatas()
		{
			if(_instance == null){
				init();
			}else{
				throw new Error('singleton');
			}
		}
		
		public static function get instance():BookDatas
		{
			if(_instance == null){
				_instance = new BookDatas();
			}
			return _instance;
		}
		
		private function init():void
		{
			_datas = [];
			var data:BookData;
			data = new BookData("ActionScript", 1000);
			_datas.push(data);
			data = new BookData("PHP", 1200);
			_datas.push(data);
		}
	}
}

■アプリケーション本体
ListTest.mxml



	
	
	
	
	
	
	
	
	
	
	
	
	
	
	

■メインに読み込む外部AS
ListTest.as

import mx.binding.utils.BindingUtils;
[Bindable]
public var bookDatas:BookDatas; 

private function init():void
{
	bookDatas = BookDatas.instance;
	initInputArea();
	initListArea();
	initSelectedViewArea();
}

private function initInputArea():void
{
	AddBtn.addEventListener(MouseEvent.CLICK, addBtnClickHD);
}

private function addBtnClickHD(e:MouseEvent):void
{
	var label:String = InputBookName.text;
	var price:int = parseInt(InputBookPrice.text);
	var data:BookData = new BookData(label, price);
	bookDatas.datas.push(data);
	BookListView.update();
}

private function initListArea():void
{
	BindingUtils.bindProperty(BookListView, "dataProvider", bookDatas, "datas");
	DeleteBtn.addEventListener(MouseEvent.CLICK, deleteBtnClickHD);
}

private function deleteBtnClickHD(e:MouseEvent):void
{
	bookDatas.datas.splice(BookListView.selectedIndex, 1);
	BookListView.update();
}

private function initSelectedViewArea():void
{
	BindingUtils.bindProperty(SelectedBookNameView, "text", BookListView, ["selectedItem", "label"]);
	BindingUtils.bindProperty(SelectedBookPriceView, "text", BookListView, ["selectedItem", "price"]);
}

カスタムコンポーネントってなによ?

カスタムコンポーネントって何かなと思ったら、FlashでいうところのMovieClipみたいなものらしい。
一回作っちゃえば、あとはいたるところに同じものをポコポコ置いていけます。
作ったあとに、カスタムコンポーネントを配置したいmxmlを開いて、デザインモードにすると、
コンポーネント一覧の一番上に「カスタム」ってフォルダがあってそこに並んでます。

作り方は簡単で
ファイル > 新規 > MXMLコンポーネント
で作れます。
ダイアログがでてきたら「ベース」っていうのがあるので、もととなるコンポーネントを選択してあげると、そいつを拡張した自作コンポーネントができるというわけです。

MXMLって、デザインとロジックがわけられないの??いいえ、わけられます

MXMLとASはちょうどhtmlとJavaScriptの関係にあてはまります。
だから、JSは外部化するのが当たり前なのに、MXMLはどうするんだろう?という疑問がはじめからありました。
そんで、調べたらMXMLを拡張したASをつくることで、イベントの設定とかをすることができるみたいです。
またこれは、FlashIDE上で、ライブラリパネルからリンケージ設定のActionScript書き出しするのにも似てます。

今回でいうと、
MyListComponentView.mxmlとMyListComponent.asがその関係にあたります。
MXMLだけですまそうとすると、<mx:Script>とかかいたりして、ソースが複雑になりやすいんですが、MXMLを拡張したMyListComponent.asを設定してあげることで、デザインとロジックが分割することができます。

Bindableの設定をMXMLに書きたくないんですけど、、、→BindingUtilsを使いましょう!

FlexにはBindableっていう便利機能があるみたいです。
これは、一度プロパティを別のプロパティにひもづけておくと、元のプロパティが変わると自動でひもづけられている方も更新されるというものです。
例)
Labelコンポーネントのtextプロパティを変数hogeにバインディング
hoge=”a” → hoge=”b”
に変更するとtextもa→bに自動で更新されます。

そんで、バインディングは普通MXMLでひもづけするみたいなんですが、MXMLにロジックはやっぱり書きたくないのが人情というもの。
調べてみると、BindingUtilsというクラスを使うといいみたいです。

BindingUtils.bindProperty(site:Object, prop:String, host:Object, chain:Object)

引数がよくわからんので上の場合の例だと

BindingUtils.bindProperty(MyLabel, “text”, this, “hoge”)

とかやるといいみたい。
そんで困ったのが、バインディングするプロパティが入れ子になっている場合
例えばMyObjectっていうオブジェクトがあったとして、
Myboject.hoge.foo.bar
っていうプロパティにバインディングしたいときどうやるの?って感じなんですが、
マニュアルみたらこんな感じにやってみて!って書いてありました。

BindingUtils.bindProperty(MyLabel, “text”, MyObject, [“hoge”, “foo”, “bar”]);

なので、配列にしてプロパティ名を順番に列挙していけばいいみたい。

ていう感じみたいです。


自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る