6 July 2009
ページ ツール |
この記事は、Flex 3フレームワークに関する知識を前提としています。
中級
Flex 4(コード名:Gumbo)リリースの主要なテーマの1つは、「Design in Mind(デザインの考慮)」であり、スキンはその重要な一部です。Flash Playerは、Webの世界で今日見られる最も創造的な作品の一部をユーザーに提供する役割を担っています。しかし、Flexアプリケーションに関しては、お互いに似すぎているという評価もあります。これは、開発者の多くがFlexのデフォルトのルックアンドフィール(Haloと呼ばれるもの)を採用し、スタイルやスキンをあまり活用していないからです。
Flex 4ベータ版では、アプリケーションのルックアンドフィールを完全に変更するのが容易になります。新しいスキンアーキテクチャは、Flex 4のその他の変更に基づいており、コンポーネントのロジックと資格的要素の明確な分離を特長としています。このため、Flex 4ベータ版のコンポーネントは、視覚的外観に関する情報を一切持っていません。このような情報はすべてスキンファイルに記録されています。FXGと新しいステート構文のおかげで、新しいスキンファイルは完全にMXMLで作成でき、読み書きが簡単であると共に、ツールによるアクセスも容易です。
この記事では、Flex 4ベータ版のスキンアーキテクチャの改良について説明します。ボタンの基本的なスキンを作成することで、FXGと新しいステート構文の概要を紹介します。次に、スライダーのスキンを作成するプロセスを通じて、コンポーネントとスキンの間の情報交換に用いられる規約を説明します。最後に、スキンを適用できる新しいコンポーネントの作成を通じて、スキン可能なコンポーネントについて詳しく説明します。
注意:このドキュメント全体を通じて、Haloコンポーネントとは、もともとFlex 3に含まれていたコンポーネントを指します。Sparkコンポーネントとは、Flex 4ベータ版の新しいコンポーネントを指します。
FXGは、Flash Playerを利用したベクターグラフィックスのための宣言型マークアップ言語です。新しいマークアップにより、カスタムボタンを容易に作成できます。このボタンの作成は、テキストが入った単純な長方形から始まります(図1を参照)。
<?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">
<s:Group verticalCenter="0" horizontalCenter="0">
<s:Rect id="rect" radiusX="4" radiusY="4" top="0"
right="0" bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>
<s:Label text="Button!" color="0x131313"
textAlign="center" verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Group>
</s:Application>
Flex 3を使用したことがあれば、上記の構文はおなじみでしょうが、使用されているコンポーネントは見たことがないかもしれません。Groupコンテナは、Sparkの基本的な飾りのないコンテナです。Rectは新しいFXGグラフィックスプリミティブであり、名前からわかるように長方形を表します。ドキュメント中の最後のコンポーネントであるSimpleTextは、Sparkの新しいテキストコンポーネントです。MXMLはコンポーネントの説明として解釈できます。これは角が丸くなった長方形であり、1ピクセルのダークグレーの線を持ち、内部は緑に塗られ、中央にテキストが表示されます。
FXGの優れた点は、プログラムの描画命令よりも理解しやすいことに加えて、XMLの構造のためにツールでの処理が容易なことです。FXGについて詳しくは、FXG仕様を参照してください。
ここまでは、MXMLドキュメントは単なるスタティックなアートワークであり、対話性を持ちません。Flex 4ベータ版の新しいスキン機能はまだ利用されていません。そのためには、Buttonコンポーネントにフックしてスキンとして使用する必要があります。Sparkのスキンファイルを作成するには、ルートタグとしてSkinを持つ新しいMXMLファイルを作成します。次に、上記のグラフィックスコードをその中にコピーします。
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<!-- border and fill -->
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0" bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>
<!-- text -->
<s:Label text="Button!" color="0x131313"
textAlign="center" verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Skin>
ファイルのステートにもう1つ追加されたものがあることにお気付きでしょう。これについては後で説明します。
スキンファイルが完成したら、それをButtonコンポーネントに関連付ける必要があります。Sparkアーキテクチャのスキン可能コンポーネントは、skinClassというCSSスタイルによってスキンと関連付けられます。このスタイルは、スタイルシートで設定することも、MXMLでインラインに設定することもできます。この例では後者の方法を使用します。
<?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">
<s:Button verticalCenter="0" horizontalCenter="0" skinClass="ButtonSkin1"
click="trace('I\'ve been clicked!')" focusIn="trace('focus...on me?')" />
</s:Application>
これで、ボタンが新しいスキンファイルにフックされました。Buttonコンポーネントには、ボタンのすべての動作ロジックが含まれます。これは、イベントリスナーを追加したり、新しいイベントを送出したり、コンポーネントがどのステートにあるかを判断したりします。スキンはそのような処理をする必要はなく、単にコンポーネントのビジュアルを定義します。
しかし、ボタンの外観は、最初に作成したスタティックなグラフィックスとまったく変わりません。ボタンは対話的になりましたが、そのようには見えません。これは、ボタンの外観が各ステートでどのように変わるかを定義していないからです。
スタティックなスキンは全然面白くありません。面白くするには、スキンとコンポーネントの間での情報のやり取りが必要です。これら2つの要素は、スキン規約の定義に従って情報をやり取りします。これには3つの部分があります。スキンステート、データ、パーツです。コンポーネント側ではこれら3つの部分を定義し、スキン側ではそれに反応します。
Sparkのスキン可能コンポーネントには、スキンステートのセットがあります。コンポーネントがどのスキンステートにあるかによって、スキンの外観を変更できます。Buttonコンポーネントには、up、over、down、disabledの4つの基本的なスキンステートがあります。各ステートで異なる外観を持つようにスキンを変更できます(図4を参照)。
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<!-- dropshadow for the down state only -->
<s:Rect radiusX="4" radiusY="4" top="0" right="0" bottom="0"
left="0" includeIn="down">
<s:fill>
<s:SolidColor color="0"/>
</s:fill>
<s:filters>
<s:DropShadowFilter knockout="true" blurX="5" blurY="5"
alpha="0.32" distance="2" />
</s:filters>
</s:Rect>
<!-- border and fill -->
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0"
bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" color.over="0x92D64E"
color.down="0x67A41D"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>
<!-- highlight on top -->
<s:Rect radiusX="4" radiusY="4" top="2" right="2" left="2"
height="50%">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF" alpha=".5"/>
<s:GradientEntry color="0xFFFFFF" alpha=".1"/>
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- text -->
<s:Label text="Button!" color="0x131313"
textAlign="center"
verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Skin>
スキンの定義に基づいて、スキンステートが変換するとコンポーネントの外観が変化します。スキンファイルでは、ステートに対する新しいドット構文が用いられています。これはFlex 4ベータ版の新機能であり、ステート変更をより明確かつ簡潔に表記できます。構文はproperty.stateName="value of that property in that state"となります。例えば、alpha.disabled=".5"とすると、ボタンがdisabledスキンステートになったときに、スキンはalphaを50%に変更します。overステートとdownステートでは、color.over="0x92D64E" color.down="0x67A41D"によって異なる色が指定されています。
新しいステート構文では、includeInとexcludeFromの2つのプロパティがすべてのMXMLコンポーネントに存在します。ボタンスキンのドロップシャドウはdownステートだけに存在し、ボタンが押されたような外観を実現します。また、ボタンの見栄えをよくするため、ボタンの上部を強調するもう1つの長方形をすべてのステートに追加しました。
注意:Flex 4の拡張されたステート構文について詳しくは、仕様を参照してください。
ボタンを操作してみると、スキンステートに応じて視覚的外観が対話的に変化することがわかります。ただし、コンポーネントのテキストは「Button」に固定されたままです。次の部分では、コンポーネントのデータ(この例ではButtonコンポーネントのlabelプロパティ)をスキンに表示する方法を示します。
スキンには必ずHostComponentメタデータを含めることをお勧めします。HostComponentメタデータは、スキンが適用されるコンポーネントを指し、スキンからコンポーネントにアクセスするために必要です。これを定義すると、スキンはコンポーネントを指すhostComponentプロパティを持つようになります。Buttonスキンで、このhostComponentプロパティを使用して、ボタンのlabelプロパティにバインドすることができます。
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
<fx:Metadata>
[HostComponent("spark.components.Button")]
</fx:Metadata>
...
<!-- text -->
<s:Label text="{hostComponent.label}" color="0x131313"
textAlign="center"
verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
</s:Skin>
ボタンが宣言されると、スキンのテキストはlabelプロパティに基づいて決まります。
<?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">
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
s|Button {
skinClass: ClassReference("ButtonSkin3");
}
</fx:Style>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button label="Button #1" />
<s:Button label="Button #2" />
<s:Button label="Button #3" />
</s:Application>
メインアプリケーションには、3つのボタンが宣言されています。各ボタンは、定義されたCSSタイプセレクターによって、同じスキンファイルButtonSkin3を使用します。しかし、ラベルはボタンごとに異なっています。スキンはlabelプロパティを取得してテキストを表示するので、ボタンは意図したとおりに異なるテキストで表示されます(図5を参照)。
ここまで、スキン規約の3つの部分のうち、ステートとデータの2つを見てきました。スキンステートは、コンポーネントから対話を引き起こす方法であり、そのステートでのコンポーネントのルックアンドフィールをスキンが定義します。データはコンポーネントのユーザー設定可能なプロパティであり、HostComponentメタデータとhostComponentプロパティを通じてスキンから取得できます。上の例では、スキンがButtonコンポーネントからデータ(labelプロパティ)を取得しています。データをやり取りするもう1つの方法は、スキンパーツを使ってスキンパーツにデータを設定することです。
スキンパーツは、スキン規約の3つめの部分です。Sparkのスキン可能コンポーネントには、コンポーネントの定義に使用できるスキンパーツのセットがあります。スクロールバーの場合、加算ボタン、減算ボタン、トラック、サムの4つのスキンパーツがあります。ボタンの場合、スキンパーツはlabelElementの1つだけです。これは、Buttonコンポーネントが要求するパーツです。上のButtonスキンでは、テキストを{hostComponent.label}にバインドする代わりに、テキストコンポーネントのIDをlabelElementにすると、Buttonコンポーネントはこのスキンパーツを認識し、ラベルプロパティをスキンに設定します。
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled=".5">
<fx:Metadata>
[HostComponent("spark.components.Button")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<!-- dropshadow for the down state only -->
<s:Rect radiusX="4" radiusY="4" top="0" right="0" bottom="0"
left="0" includeIn="down">
<s:fill>
<s:SolidColor color="0"/>
</s:fill>
<s:filters>
<s:DropShadowFilter knockout="true" blurX="5" blurY="5"
alpha="0.32" distance="2" />
</s:filters>
</s:Rect>
<!-- border and fill -->
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0"
bottom="0" left="0">
<s:fill>
<s:SolidColor color="0x77CC22" color.over="0x92D64E"
color.down="0x67A41D"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x131313" weight="2"/>
</s:stroke>
</s:Rect>
<!-- highlight on top -->
<s:Rect radiusX="4" radiusY="4" top="2" right="2" left="2" height="50%">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF" alpha=".5"/>
<s:GradientEntry color="0xFFFFFF" alpha=".1"/>
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- text -->
<s:Label id="labelDisplay" color="0x131313" textAlign="center"
verticalAlign="middle"
horizontalCenter="0" verticalCenter="1"
left="12" right="12" top="6" bottom="6"
/>
<!-- transitions -->
<s:transitions>
<s:Transition>
<s:CrossFade target="{rect}" />
</s:Transition>
</s:transitions>
</s:Skin>
ここではSimpleTextはホストコンポーネントにバインドされていません。その代わりに、labelElementというIDを付けることによって、Buttonコンポーネントが探しているパーツにします。Buttonコンポーネントはデータを伝達する役割を果たし、labelプロパティをlabelElementに設定します。
ここでは、ラベル要素のスキンパーツを指定するほかに、単純なCrossFadeトランジションをスキンに加えています。スキンファイルには、トランジションを初めとするコンポーネントのすべての視覚的側面が定義されます。この例では、ボタンのステートが変化すると、ステート間でフェードトランジションが実行されます。
スキンパーツの役割は、コンポーネントからスキンにデータを設定することだけではありません。コンポーネントはこれを使って、動作をフックすることもできます。これを説明するため、スライダーコントロールを例に取ります。スライダーには、トラックとサムの2つの主要なパーツがあります。この例では、コンポーネントは表示するスキンパーツにデータを設定する代わりに、パーツにイベントリスナーを追加し、コンポーネントのvalueプロパティに基づいてサムのレイアウトを実行しています。例えば、トラックがクリックされると、コンポーネントはvalueプロパティを更新し、サムの位置を適切に設定します。この他に、ダイナミックなスキンパーツdataTipが存在し、サムをドラッグしたときにポップアップ情報を表示するために使用されます。図6に示すのは、変更された単純なスライダーの例です。
これを実現するには、スキンファイルにthumb、track、dataTipの3つのスキンパーツが宣言されている必要があります。
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
minWidth="11" minHeight="100" alpha.disabled="0.5">
<fx:Metadata>
[HostComponent("spark.components.VSlider")]
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<fx:Declarations>
<fx:Component id="dataTip">
<s:DataRenderer minHeight="24" minWidth="40" x="20">
<s:Rect top="0" left="0" right="0" bottom="0">
<s:fill>
<s:SolidColor color="0xFFF46B" alpha=".9"/>
</s:fill>
<s:filters>
<s:DropShadowFilter angle="90" color="0x999999" distance="3"/>
</s:filters>
</s:Rect>
<s:Label id="labelField" text="{data}"
horizontalCenter="0" verticalCenter="1"
left="5" right="5" top="5" bottom="5"
textAlign="center" verticalAlign="middle" color="0x555555" />
</s:DataRenderer>
</fx:Component>
</fx:Declarations>
<s:Button id="track" left="5" right="5" top="0" bottom="0" skinClass="MyTrackSkin" />
<s:Button id="thumb" left="0" right="0" width="18" height="8" skinClass="MyThumbSkin" />
</s:Skin>
これらのスキンパーツがスキンで定義されていれば、それを利用するのはコンポーネントの役割です。コンポーネントはサムにイベントリスナーを追加して、サムをトラック上でドラッグできるようにします。また、値に基づいてサムの位置を設定します。サンプルソースコードでMyTrackSkinとMyThumbSkinを確認してください。FXGの実際の使用例が見られます。ここで定義されているサムのスキンは、デフォルトのSparkスキンのサムとはまったく違った形をしています。
dataTipスキンパートはダイナミックです。このパーツはコンポーネントが作成してレイアウトします。この例では、サムをドラッグしたときに、dataTipがポップアップし、サムの右側に配置されます。スキン規約によれば、スキンはスキンパーツとその視覚的側面を定義するだけで、パーツの動作を指定する必要はありません。動作のためのロジックはすべてコンポーネントが処理します。
注意:Flex 4ベータ版の組み込みコンポーネントの多くは、スキンパーツを動作の割り当てだけでなく、データの設定にも使用しています。スキンにデータを伝達するもう1つの方法は、hostComponentプロパティを通じて取得することです。
コンポーネントのスキンを作成する際に、すべてのスキンパーツの定義が必要というわけではありません。例えば、VSliderのdataTipスキンパーツは必須ではありません。定義されていなければ、データのヒントが表示されないだけです。
スキン可能なSparkコンポーネントは、何か特別なことを裏で行うわけではありません。これらのコンポーネントは、データプロパティを持ち、必要なスキンパーツとスキンステートをメタデータを通じて通知します。また、スキンとスキンパーツのライフサイクルを管理するためのいくつかの重要なメソッドをフックします。同じことを行う新しいスキン可能コンポーネントを簡単に作成できます。
これを示すために、単純なNoteCardコンポーネントを作成してみましょう。これは、画面上にメモを表示するものです。図7に示す例では、アプリケーションはランダムな引用を書き込んだ複数のメモを画面上に作成しています。
メインアプリケーションは、単にNoteCardをランダムな引用で作成し、少し回転するだけです。アプリケーションの重要な部分はNoteCardクラスです。これはspark.components.supportClasses.SkinnableComponentクラスを拡張し、スキンライフサイクルメソッドをフックしています。
package
{
[SkinState("normal")]
[SkinState("disabled")]
public class NoteCard extends SkinnableComponent
{
public function NoteCard()
{
super();
}
[SkinPart(required="true")]
public var labelDisplay:TextBase;
[SkinPart(required="false")]
public var closeButton:Button;
private var _text:String;
public function get text():String
{
return _text;
}
public function set text(value:String):void
{
if (_text == value)
return;
_text = value;
}
...
}
}
このコンポーネントは、データプロパティ、スキンステート、スキンパーツを定義しています。データに関しては、NoteCardにはパブリックのtextプロパティがあります。また、NoteCardには2つのスキンステートnormalとdisabledがあり、クラスの先頭でSkinStatesメタデータによって宣言されています。これにより、スキンにはこれら2つのステートを実装する必要があることがわかります。
NoteCardにはまた、2つのスキンパーツがあり、SkinPartメタデータで宣言されています。SkinPartメタデータは、スキンパーツ名のすぐ上にあります。この例では、labelElementは必須のTextGraphicElementスキンパーツであり、closeButtonはオプションのButtonスキンパーツです。
スキンは実行時にロードされるので、コンポーネントが最初に起動したときには、スキンが存在する保証はありません。また、スキンパーツも(特にオプションのものは)すべて存在するとは限りません。スキンで宣言されたパーツをコンポーネントのプロパティ定義にフックし、それらが使用可能になったことをスキンライフサイクルメソッドを通じてコンポーネントに通知するのは、フレームワークの役割です。
スキンステートをフックするには、getCurrentSkinState をオーバーライドして、スキンが現在あるべきステートを返すようにします。この例では、これは"normal"または"disabled"を返します。何らかのイベントによってスキンステートが無効になった場合、コンポーネントはinvalidateSkinState を呼び出す必要があります。
package
{
[SkinState("normal")]
[SkinState("disabled")]
public class NoteCard extends SkinnableComponent
{
...
override public function set enabled(value:Boolean) : void
{
if (enabled != value)
invalidateSkinState();
super.enabled = value;
}
override protected function getCurrentSkinState() : String
{
if (!enabled)
return "disabled";
return "normal"
}
...
}
}
enabledプロパティが設定されると、setterはinvalidateSkinState を呼び出します。これによりスキンは、ステートの変更が必要なことを知り、getCurrentSkinState を呼び出します。
スキンパーツをフックするには、partAdded とpartRemoved の2つのメソッドをフックします。これらのメソッドは、特定のスキンパーツが追加されたことと、削除されたことを通知します。パーツが追加または削除されるのは、スキンがロードされたとき、スキンが実行時に交換されたとき、特定のステートだけに存在するパーツが遅延されていて後でオンラインになったとき、またはダイナミックパーツが新規作成されたときです。パーツが追加されたことを知ったら、必要なデータを設定したり、必要なイベントリスナーをフックしたりします。パーツが削除されたことを知ったら、その逆の操作を実行します。
package
{
public class NoteCard extends SkinnableComponent
{
[SkinPart(required="true")]
public var labelDisplay:TextBase;
[SkinPart(required="false")]
public var closeButton:Button;
public function set text(value:String):void
{
if (_text == value)
return;
_text = value;
if (labelDisplay)
labelDisplay.text = value;
}
override protected function partAdded(partName:String, instance:Object) : void
{
super.partAdded(partName, instance);
if (instance == labelDisplay)
labelDisplay.text = _text;
if (instance == closeButton)
closeButton.addEventListener(MouseEvent.CLICK, closeButton_clickHandler);
}
override protected function partRemoved(partName:String, instance:Object) : void
{
super.partRemoved(partName, instance);
if (instance == closeButton)
closeButton.removeEventListener(MouseEvent.CLICK, closeButton_clickHandler);
}
protected function closeButton_clickHandler(event:MouseEvent) : void
{
event.stopPropagation();
IVisualElementContainer(parent).removeElement(this);
}
}
}
partAdded()では、labelElementがフックされたときに、textプロパティをこのスキンパーツに設定します。また、text setterでは、labelElementが存在してフックされているかどうかをチェックし、存在する場合はlabelElementのtextプロパティをコンポーネントと同期させます。partAdded()では、closeButtonスキンパーツにクリックイベントリスナーを追加します。partRemoved()では、このクリックイベントリスナーを削除します。
この強力なスキンの仕組みを利用するために、SkinnableComponentに必要なことはこれだけです。このコンポーネントのスキンを作成する場合、意図した動作を実現するためには、スキンステートを実装し、スキンパーツをフックする必要があります。図6に示す黒板のスキンは、サンプルソースファイル中にあります。これは単純なコンポーネント定義ですが、別のスキンを使用することでルックアンドフィールを完全に変えることができます。これがスキンの真の威力です。
注意:スキン可能コンポーネントを作成する際には、ある動作がコンポーネントに属するかスキンに属するかを決めなければならない場合があります。このための明確な規則は存在しません。作業が容易になるように決めてください。ただ、一般的な指針としては、コンポーネントのルックアンドフィールを定義する情報はすべて、スキンファイル中にMXMLで定義すべきです。一方、複数のスキンで特定の動作が必要になる場合、その動作をスキン可能コンポーネントに入れるのがいいかもしれません。例えば、スライダーのサムの配置は、スキンでなくVSliderとHSliderで行われます。
Flex 4ベータ版では、スキンに大きな変更が加えられています。コンポーネントとスキンの間に明確な分離が設けられました。コンポーネントには、コンポーネントのデータ、動作、コアロジックが含まれ、スキンはコンポーネントのルックアンドフィールを定義します。コンポーネントはActionScript、スキンはMXMLで作成します。これは、FXGと新しいステート構文によって可能となりました。コンポーネントとスキンは、スキン規約を通じて互いに情報をやり取りします。これらは別のファイルなので、スキンを入れ替えることによって、コンポーネントのルックアンドフィールを完全に変えることができるようになりました。
Flex 4ベータ版のスキンについて詳しくは、スキンアーキテクチャ仕様と、Gumboコンポーネントアーキテクチャホワイトペーパーを参照してください。