Flex カス タムコン ポーネン ト の 作 り 方 ( 有 )CO-CONV 最田 健一
自己紹介
にとよん という名前でブログやってま す
Agenda 1.Flex 概要 2. 非カスタムコンポーネント な開発 3. カスタムコンポーネント開 発 4. まとめ
1
Flex 概要
Flash と ActionScript がベース
しかし
タイムライン が
ない
プログ ラマ用
Flash やっ てた人よ り
Java や C# 経験者 の方が とっつきやす い
特徴
豊富な GUI パーツ
XML で 配置
具体例
具体例
具体例
具体例
具体例
流行し 始め
Anywhere.FM
SearchMash ( Google の検索実験サイト)
Google Analytics AIR beta ※ これは AIR だが UI は Flex で作られている
弊社某案件
2
非カスタ ムコン ポーネン トな開発
鉄則
可能な限り 既存のコン ポーネント を使おう
複雑 な 塊 には 複合コンポー ネント を定義
例
複合コンポーネント化
DateRange.mxml
利点
構造が すっきり
実装の 責任範囲 が明確に
再利用性 UP
注意点
大きなクラスも問題だ が
分けすぎにも注意
バランスが大事
既存のコン ポーネントに 不満があれば
3
カスタム コンポー ネント開 発
大きく分け て 3通りの方 法
1 既存コンポーネント の 拡張 2 既存コンポーネント の 再実装 3 新規コンポーネン ト
1 既存コンポーネント の 拡張 既存コンポーネン トを 継承 して 機能を追加
コンポーネン トのクラス階 層
UIComponent Button ScrollControlBase ListBase Tree DataGrid
UIComponent ListBase Button Tree DataGrid ScrollControlBase MyTree MyButton
新たなプロパ ティ や メソッド を 追加 できる
protected な メソッ ド や プロパティ を 使って色々できる
super の 前後に コードを入れ て色々できる
もしも、 継承では限界 がある場合 は
つまり、 private にアクセス したいときは
2 既存コンポーネント の 再実装 既存コンポーネントの ソースをコピーして 一部書き換える
UIComponent ListBase Button Tree DataGrid ScrollControlBase MyTree MyButton コピー
mx.controls.Button のソースコードは frameworks\source\mx\ controls\Button.as
mx.controls.Button のソースコードは frameworks\source\mx\ controls\Button.as ( 2,355 行 !!! )
あまりお薦め しない
ソースが 煩雑になる
ライセンス 的 に 微妙
開発 は OK ソース公開 NG 詳しくは、、、 Flex SDK の 「 license.htm 」をご覧くだ さい
2 3 新規コンポーネン ト 1からコンポーネン トを 作る場合
UIComponent Button ScrollControlBase ListBase Tree DataGrid MyComp UIComponent を 継承する
UIComponent って何?
その前に、 ありがちな 実装例
円を描画する コンポーネン ト
<mx:Application xmlns:mx=" xmlns:comp="*"> <comp:Circle text="test" color="#ffffff" backgroundColor="#336699" width="100" height="100"/> 使用例
Package { import flash.text.*; import flash.events.Event; import mx.core.UIComponent; public class Circle extends UIComponent{ // テキスト private var textField:TextField; (つづく) } 実装例 (1/6) – クラス定義
/****** color プロパティ ******/ // 変数定義 private var _color:uint; // getter public function get color():uint { return _color; } // setter public function set color(value:uint):void { _color = value; dispatchEvent(new Event("colorChange")); } 実装例 (2/6) – プロパティ
/****** backgroundColor プロパティ ******/ // 変数定義 private var _backgroundColor:uint; // getter ・ setter は同様のため略 /****** text プロパティ ******/ // 変数定義 private var _text:String; // getter ・ setter は同様のため略 実装例 (3/6) – プロパティ (cont.)
// コンストラクタ public function Circle() { // TextField 作成 textField = new TextField(); addChild(textField); // イベント登録 addEventListener("colorChange", colorChangeHandler); addEventListener("backgroundColorChange", bgColorChangeHandler); addEventListener("textChange", textChangeHandler); } 実装例 (4/6) – コンストラクタ
private function colorChangeHandler(event:Event):void { render(); } private function bgColorChangeHandler(event:Event):void { render(); } private function textChangeHandler(event:Event):void { render(); } 実装例 (5/6) – イベントハンド ラ
// 描画処理 private function render():void { graphics.clear(); graphics.beginFill(backgroundColor); graphics.drawEllipse(0, 0, unscaledWidth, unscaledHeight); graphics.endFill(); var tf:TextFormat = textField.getTextFormat(); tf.color = color; tf.size = 30; textField.defaultTextFormat = tf; textField.text = text ? text : ""; } 実装例 (6/6) – 描画処理
できた!
問題点
イベント処 理が煩雑
プロパティの数だ け イベントハン ドラ が増える
パフォーマ ンスの問題
circle.text = " hoge " ; circle.color = 0xffff00; circle.backgroundColor = 0xff0000; このコードは 描画処理が3回走る
UIComponent で解決!
無効化メソッ ドの活用
// setter public function set color(value:uint):void { _color = value; dispatchEvent(new Event("colorChange")); invalidateDisplayList(); } setter で 無効化メソッドを呼 ぶ
次の画面更新で 描画処理が 行われる invalidateDisplayList()
addEventListener と イベントハンド ラ は、 いらないの で削除
override protected function updateDisplayList(w:Number, h:Number):void { super.updateDisplayList(w, h); // 忘れずに !! render(); } updateDisplayList で描画する
1度でも無効化され ると、次の画面更新 で Flex システムが 呼び出すメソッド updateDisplayList()
circle.text = " hoge " ; circle.color = 0xffff00; circle.backgroundColor = 0xff0000; 3回 invalidate される が 描画処理は1回だけ
(補足) 無効化メソッ ド3種類
1. 描画処理 invalidateDisplayList ↓ updateDisplayList
2. サイズ処 理 invalidateSize ↓ measure
3. プロパティ変更処 理 invalidateProperties ↓ commitProperties
さらに チューニング
// change フラグ private var colorChanged:Boolean = false; // setter public function set color(value:uint):void { _color = value; colorChanged = true; dispatchEvent(new Event("colorChange")); invalidateDisplayList(); } changed フラグを導入
// 描画処理 private function render():void { // ( 略 ) if(colorChanged) { colorChanged = false; var tf:TextFormat = textField.getTextFormat(); tf.color = color; tf.size = 30; textField.defaultTextFormat = tf; } textField.text = text ? text : ""; } changed フラグが true のとき のみ描画に反映
// 描画処理 private function render():void { // ( 略 ) if(colorChanged) { colorChanged = false; var tf:TextFormat = textField.getTextFormat(); tf.color = color; tf.size = 30; textField.defaultTextFormat = tf; } textField.text = text ? text : ""; } changed フラグが true のとき のみ描画に反映 この部分が重い処理の場合に 速度が向上する
さらに さらに チューニング
// コンストラクタ public function Circle() { // TextField 作成 textField = new TextField(); addChild(textField); } コンストラクタで 子を作成するのをやめる
// コンストラクタ public function Circle() { } override protected function createChildren(){ super.createChildren(); // TextField 作成 textField = new TextField(); addChild(textField); } コンストラクタで 子を作成するのをやめる
createChildren() は addChild されたとき に Flex が呼ぶメソッド
new だけされて addChild されない場合、 パフォーマンスが向上 するだけでなく
初期化のコードを createChildren() に 集約 できる
無効化メソッド・ createChildren の嬉しいところ
コーディング は 煩雑になるが 多少
書く場所が 一意に定まる
スパゲッティ になりがちな UI をすっきり 書ける
UIComponent こそが Flex の 肝
UIComponent は フレームワーク だ
4
まと め
基本は標準コンポーネントを使 う 不満があれば継承して拡張する どこにもなければ、 UIComponent を継承して、1か ら作る
参考資料 Flex コンポーネントの作成と拡張 flex2_createextendcomponents.pdf 前回よりは成長したブログ