UIComponentカスタムクラスのお作法

カスタムコンポーネントは要するにUIComponentを継承して作成すればいいわけですが、
うっかりすると再利用性の低いコンポーネントを作ってしまいます。


いちばんやってしまうのが「コンストラクタの引数にデータモデルを指定」。
これはなるべく避けてください。
ActionScriptから動的に生成する場合には便利ですが、mxmlでRepeaterを使ったり、ItemRendererに
直したいと思った瞬間に、自らの愚かさに頭を抱えるハメになります。
いちばんいいのは、dataプロパティのみにモデルを集中して格納すること。
こうしておくと、ItemRendererとしても使えるので、再利用性が劇的に高くなります。


違う形式のプロパティを追加する場合には、setterで「入れ替える前のプロパティインスタンス」から
イベントリスナーをはずしておくようにしましょう。
weakReferenceより確実で、Flex2の一部のコードでもそうしています。


そしてこれは設計にもよるのですが、FlexEvent.REMOVEのイベントリスナーを用意しておき、
そのなかでモデルを消去するか、モデルへのイベントリスナーをはずす処理を追加すると、
後々のトラブルを回避できます。
これは、画面から消去されたあとでも、コンポーネント自身はガベージコレクション
走るまでメモリに残っており、イベントリスナーはその間機能し続けることを指しています。
これのおかげでガベージコレクションがうまく動作せず、最終的にメモリ不足を引き起こす最悪のケースもあります。


そして、描画に関すること。
チュートリアルにある「カスタムコンポーネントの作成」は結構難解ですが、
要するに「描画に関すること(graphicsをいじる操作)」はupdateDisplayList()を、
座標変換や移動に関することはCommitPropertiesをオーバーライドして、処理を追加するとうまくいきます。
コンポーネントの一部として埋め込んだShapeなどを移動させたいだけならinvalidatePropertiesを呼べばいいし、
中のgraphicsまで更新したいときには続いてinvalidateDisplayListを呼べばよくなります。
これは、処理を軽くするための標準的なアプローチです。


カスタムコンポーネントの動きは、コンポーネント内部だけで解決するのが理想です。
Commandパターンを使って一度に複数のコンポーネント(のグラフィカルコンテキスト)を更新する、というのは
C#JavaMFCに慣れている人にとってはやりやすいですが、ActionScriptの場合は
それぞれのコンポーネントが描画タイミングを別々に管理しているため、速度的に不利になります。


描画はすべて、内包するモデルオブジェクトに対してイベントを投げることで行うようにするのが楽ですが、
コンポーネントの動作それぞれにenabledプロパティを持たせておくと、モデルの更新にいちいち見た目を変化させない
コンポーネントになるので便利です。


そして、描画や状態を更新したら、それを独自のイベントとして自分自身にディスパッチする癖をつけるべきです。
これはコンポーネントのテストやデバッグ時に役に立ちますし、Eventタグを定義しておくだけで
他のコンポーネントから利用しやすくなります。
この有用性は、mxmlに埋め込んだときに実感できます。