Flex ActionScript 関連覚書などなど

Frog on AIRさんのサイトで、こんな記事がありました。

オブジェクトのサイズを取得できない(AIR β2/β3)

記事の内容は、mx.controls.Butttonのインスタンスを生成した直後に、widthとheightの値を確認すると0になってしまう。というようなものです。

実際僕も何か作っているとき、同じような状況を何度も経験しました。
ホント大ハマリして、何時間も費やしたり・・・。
自分の備忘録も兼ねて、少しこのあたりを書き残しておきます。

クラスの種類
Flex2のリファレンスで説明されているクラスの中には、
純粋なActionScript3.0のクラスとFlex2のクラスの2種類があります。

純粋なActionScript3.0のクラスとは、
Array、Number、SpriteやTextFieldなどのクラスで、
importするときのクラスパスが、flash.~のものです。

対して、Flex2のクラスとは、
UIComponent、Button、Alert、PopUpManagerなどなど、
importするときのクラスパスが、mx.~のものです。

純粋なActionScript3.0のクラスというのは、
ActionScript3.0という言語でプログラミングをする場合には基本的に使えるクラスで、
FlexBuilder2でもFlashCS3でも使えるはずです。
一方Flex2のクラスというのは、
上記純粋なActionScript3.0のクラスを拡張(継承)したクラスで、
Flex2SDKのコンパイラでは一緒に提供されているだけです。
Flex2のクラスというのは、つまり、ActionScript3.0でプログラムする場合に、
使用できるオプション的なクラス郡になります。

例えばButtonクラスならSpriteを継承したクラスFlexSprite、
をさらに継承したUIComponentクラス、
をさらに継承したものがButtonクラスです。

Flex2のクラス
Flex2のクラスはFlexフレームワーク上で動作することを前提に作成されています。
つまりいくつかのフレームワークのルールに従う必要があるということです。

このルールのひとつとしてFlex2フレームワークを用いる場合には、
多くの便利なビジュアルコンポーネントを利用できるようになる代わりに、
独自のDisplayObjectを表示させたい場合には、
UIComponentクラスを継承しなければならないというルールがあります。
(IUIComponentインターフェースでもいいのかな・・・?)

UIComponentクラスでは、
コンストラクタでは最低限のプロパティとイベントリスナの初期化しか行いません。
(このため、インスタンス生成直後にはwidthなどは0になります。)
コンポーネントがDisplayObjectのツリー上にaddChildされるたあと
initialize()メソッドが呼ばれ、描画に必要なプロパティの一部がセットされます。
その後、実際に描画されるタイミングでupdateDisplayListというメソッドで、
レイアウトやサイズ等の値が計算され(ここでwidth等の値が確定します)、描画されます。
もちろんaddChildメソッドもoverrideして、子DisplayObjectを自身に追加する際には、
子DisplayObjectのinitializeメソッドを呼び出すようにしてあります。

と、いうことで一番初めのButtonクラス生成直後にwidth、heightの値が0となる件にやっと繋がりました。Flex2のDisplayObject系のクラスでは、処理の無駄を省くため、プロパティ実際のビジュアル部分のレイアウトやサイズ等の計算は次の描画タイミング時まで保留されます。そのため、すぐにwidthやheightの値を取得することができません。

以下、対応策の案としては、

1.Flex2のクラスを使わない
元も子もないですが、使わないというのも一手ですよね。
全部flashパッケージ内から賄い、足りない部分は自分で作る、と。
ボタンくらいだったら、SimpleButtonクラスでも十分なことも多いです。

2.callLaterメソッド
UIComponentクラスで定義されているcallLaterメソッドを使います。
(参考:callLaterメソッドの使用)

callLater() メソッドは、現在の更新ではなく、次の画面更新で実行する処理をキューに格納します。

つまりcallLater(hogeMethod)を用いることで、
コンポーネントが描画される(描画用のレイアウト・サイズ計算処理などが終了した)ときに
hogeMethodが呼ばれるので、widthなどの値を取得することができます。

今回のように初期化時だけであれば、
creationCompleteイベントをハンドルしても良いかもしれませんね。

コメント

コメント(2) “[Flex]コンポーネントのサイズがゼロになる?”

  1. Jintenさん、こんにちは。Frog on AIRの中の人です。
    疑問にお答えいただいて、ありがとうございました。

    タイミングの問題だと予想はついたので、イベント系はひと通り試したつもり
    だったのですが、どうも抜けてたようです。

    いずれにしましても、仕組み自体あまり理解しないまま、あれこれいじくって
    ますので、今回のご解説は大変参考になりました。

  2. ken

    どうも。jintenです。

    このあたりの話は僕自身もたまにはまるところですし、
    はまる人も多いのかな~なんて思って、書いてみた次第です。
    お役に立てたのならうれしいです。

コメントする