このマスターシリーズでは、Flash Builder 4.5およびAdobe AIRを使用したFlexモバイルアプリケーションの開発について解説します。

本記事では、Flexモバイルプロジェクトのコンポーネントで使用される、モバイルスキンクラスについて解説します。なお記事では、Flash Builder 4.5にバンドルされている標準のFlex SDK(バージョン 4.5.0.20967)を対象としています。

Flexテーマ

Flexテーマは、コンポーネントのスタイルやスキンのテンプレートです。原則的に、Flexモバイルプロジェクトで使用するSparkコンポーネントのクラスは、PC版Flex 4アプリケーションで使用するSparkコンポーネントのクラスと同じものですが、それぞれのコンポーネントに適用される「Flexテーマ」は異なります。

Flexモバイルプロジェクトのプロパティを開き、Flexテーマのプロパティを見てみましょう。PC版のプロジェクトの場合、「Spark」や「Wireframe」などの主要テーマやその他のサンプルテーマもありますが、モバイル版のプロジェクトの場合は、「Mobile」の一択しかありません。

スタイルとスキンの関係

スキンは、対象コンポーネントの外観を構築するために、対象コンポーネントの子表示オブジェクト(skinプロパティ)として存在します。そして、対象コンポーネントのスタイルは、子表示オブジェクトであるスキンに作用します(スキン内部から定義されたスタイルプロパティの値を取得して、外観に反映させます)。

図3は、コンポーネントとスキン、およびスタイルの関係を表したものです。定義したスタイルを表示に反映するかしないかは、スキンの内容によって変わります。つまり、テーマが変わることによって、同一コンポーネントでもスタイルが反映されたり、反映されなかったりするケースが存在するということになります。

モバイル対応コンポーネント

現在、最新のリリースビルド版であるFlex SDK 4.5.0.20967では、次のコンポーネントがモバイル対応しています(これらにはMobileテーマが適用されます)。なお、PC版Flexアプリケーションで使用できるコンポーネントが、そのまますべて利用できるわけではないという点に注意してください。

モバイル対応コントロール

  • BusyIndicator
  • Button
  • ButtonBar
  • BitmapImage
  • CheckBox
  • HSlider
  • Image
  • Label
  • List
  • RadioButton
  • RadioButtonGroup
  • Scroller
  • TextArea
  • TextInput

モバイル対応レイアウト

  • DataGroup
  • Group
  • HGroup
  • TileGroup
  • VGroup

モバイルコンポーネントのスタイルとスキンの格納場所

Mobileテーマの標準スタイル(default.css)は、次のフォルダに格納されています。

≪SDK folder≫/frameworks/projects/mobiletheme/default.css

モバイル専用スキンは、次のフォルダに格納されています。この中には、基本的なコンポーネント以外に、モバイルフレームワーク専用コンポーネントであるViewクラスやViewNavigatorクラスのスキンも格納されています。

≪SDK folder≫/frameworks/projects/mobiletheme/src/spark/skins/mobile

モバイルコンポーネントスキンの特徴

default.css内にて定義されているスキンクラスについて解説します。

ActionScriptベースのスキンクラス

基本的にSparkテーマのスキンクラスは、Groupクラスを継承したSkinクラスをベースにしたMXMLで構築されています。一方、Mobileテーマが提供するスキンクラスは、ほぼすべてUIComponentを継承したMobileSkinクラスをベースにしたActionScriptで構築されています。

実装難易度は高くなりますが、カスタムスキンクラスを作成するときには、各MobileSkinクラスのサブクラスをベースにすることを推奨します。

また、従来のSkinクラスまたはSparkSkinクラスを継承したスキンを作成することも可能ですが、特に汎用性の高いスキンクラスの場合、パフォーマンスの観点から推奨できません(ただし例えば、1点かぎり、かつサイズ固定といった条件下で使用するスキンの場合はこの限りではありません)。

FXG(Flash XML Graphics format)によるスキンの外観構成

Mobileテーマで定義できるスタイルプロパティの数は、Sparkテーマのスタイルプロパティと比べて少なく、実現できることが限られます。例えば、Buttonコンポーネントの角丸サイズを変更したい場合、Sparkテーマであれば、cornerRadiusスタイルプロパティの値を変更するだけでボタンの角丸度合いは変わりますが、MobileテーマにはcornerRadiusスタイルプロパティが用意されていません。

それは、Mobileテーマのスキンの外観がFXGで定義されているためです。変色やレイアウト、および文字修飾を除く、ほとんどのプログラマティックな機構が無効化されます。つまり、スキンを作成する際、色/レイアウト/文字装飾以外の要素は、ActionScriptではなくFXGで定義する必要があります。

また、モバイルコンポーネントのスキンでは、コンポーネントの状態(upやdownなど)に応じて、FXGを動的に丸ごと差し替えるような仕組みが採用されています。

自作FXGの実装

自作FXGを実装したカスタムButtonスキンを作成してみましょう(サンプル:CustomButtonSample.fxp)。本記事では、spark.skins.mobile.ButtonSkinクラスの作法にのっとり、upステート用FXGと、downステート用FXGを作成します。

FXGは、Creative Suite製品(Photoshop、Illustrator、Fireworks、Flash Professional、Flash Catalyst)を使用して作成することができます。通常通りにグラフィックを作成して、別名保存でFXG形式を選ぶだけです。なお、FXG形式で書き出せるのは、CS5以上となります。

また、Flex 4のグラフィックエレメントに精通している方は、エディタで直接FXGをコーディングするのも1つの手段です。例えば、次のようなFXGを用意します(upステート用FXGです)。

ソースコード:CustomButtonSample/src/skins/assets.graphics/CustomButtonUp.fxg

<?xml version="1.0" encoding="utf-8" ?> <!-- CustomButtonUp.fxg は、CustomButtonSkin で使用する up ステートスキンです。 @author taiga --> <Graphic xmlns = "http://ns.adobe.com/fxg/2008" version = "2.0" viewHeight = "50" viewWidth = "200" scaleGridLeft = "25" scaleGridTop = "25" scaleGridRight = "175" scaleGridBottom = "26" > <!-- border --> <Path data="M 0 25 q 0 -25 25 -25 h 150 q 25 0 25 25 v 1 q 0 25 -25 25 h -150 q -25 0 -25 -25 v -1 z"> <fill> <SolidColor color="#333333"/> </fill> </Path> <!-- fill --> <Path data="M 1 25 q 0 -24 24 -24 h 150 q 24 0 24 24 v 1 q 0 24 -24 24 h -150 q -24 0 -24 -24 v -1 z"> <fill> <LinearGradient rotation="90"> <GradientEntry ratio="0" color="#cccccc"/> <GradientEntry ratio=".5" color="#333333"/> <GradientEntry ratio="1" color="#666666"/> </LinearGradient> </fill> </Path> <!-- highlight --> <Path data="M 1 25 q 0 -24 24 -24 h 150 q 24 0 24 24 v 0.5 h -198 z"> <fill> <LinearGradient rotation="90"> <GradientEntry color="#999999" ratio="0.1" alpha=".1" /> <GradientEntry color="#999999" ratio="1.0" alpha=".3" /> </LinearGradient> </fill> </Path> </Graphic>

downステート用FXGについては、サンプルのCustomButtonDown.fxgをご覧ください。

FXGファイルを作成したら、プロジェクトのsrc/skins/assets.graphicsに格納します(Creative Suite製品、エディタ、どちらで作成した場合も格納する場所は同じです)。

次にspark.skins.mobile.ButtonSkinクラスを継承したCustomButtonSkin.asを作成します。

作成したCustomButtonSkinクラスの中で、作成したFXGの外観を定義します。FXGは、SpriteVisualElementのサブクラスなので、ActionScriptやMXML上から直接参照することが可能です。

spark.skins.mobile.ButtonSkinクラスには、upBorderSkinプロパティとdownBorderSkinプロパティが用意されているので、それぞれのプロパティに対して作成したFXGを設定します。さらに、自作FXGを使用する場合、spark.skins.mobile.ButtonSkinクラスのdrawBackground()メソッドが描画に弊害を及ぼすので、オーバーライドして無効化します。具体的なクラスの内容は次の通りです。

ソースコード:CustomButtonSample/src/skins/CustomButtonSkin.as

package skins { import skins.assets.graphics.CustomButtonDown; import skins.assets.graphics.CustomButtonUp; import spark.filters.DropShadowFilter; import spark.skins.mobile.ButtonSkin; /** * <p>CustomButtonSkin クラスは、CustomButtonUp.fxg と * CustomButtonDown.fxg を外観に利用したサンプルスキンクラスです。</p> * @author taiga */ public class CustomButtonSkin extends ButtonSkin { /** * <p>共用フィルタ</p> */ protected static const FILTER:DropShadowFilter = new DropShadowFilter(5, 90, 0x999999, 1, 10, 10); /** * <p>コンストラクタ</p> */ public function CustomButtonSkin() { super(); minWidth = 200; minHeight = 51; upBorderSkin = CustomButtonUp; downBorderSkin = CustomButtonDown; filters = [FILTER]; } /** * @private * 自作FXGを使用する場合、弊害を及ぼすので無効化します。 */ protected override function drawBackground( unscaledWidth:Number, unscaledHeight:Number):void {} } }

実際に作成したスキンをButtonにセットすると、次のようになります。

DPI(画面密度)への配慮

モバイル端末には様々な寸法や解像度、画面密度(DPI - Dot Per Inch)のモデルがあります。これらの端末に対応した柔軟なアプリケーションを開発するときには、特にDPIを気にしなければなりません。

Flexモバイルフレームワークが提供するDPIサポート

ActionScript 3.0には、flash.system.Capabilities クラスにCapabilities.screenDPIという、1インチあたりのドット数(dpi)を取得する読み取り専用のクラスプロパティが用意されています。このプロパティを使用することで、アプリケーションを実行しているモバイル端末の画面密度を知ることができます。

さらに、Flexのモバイルフレームワークでは、「160」「240」「320」の3つの画面密度に適したサイズのスキン外観が用意されており、Capabilities.screenDPIプロパティから取得した画面密度から、「160」「240」「320」のいずれかの近似値を算出し、画面密度に一番適切な外観(FXG)をセットします。

※自作でFXGを作成する際は、これら3つの解像度の分を用意する必要があります。

算出された画面密度は、MobileSkinのapplicationDPIプロパティで確認できます。実際に、spark.skins.mobile.ButtonSkinでは次のように記述されています。

spark.skins.mobile.ButtonSkin.asの一部

public function ButtonSkin() { super(); switch (applicationDPI) { case DPIClassification.DPI_320: { upBorderSkin = spark.skins.mobile320.assets.Button_up; downBorderSkin = spark.skins.mobile320.assets.Button_down; //( 中略 ) break; } case DPIClassification.DPI_240: { upBorderSkin = spark.skins.mobile240.assets.Button_up; downBorderSkin = spark.skins.mobile240.assets.Button_down; //( 中略 ) break; } default: { // default DPI_160 upBorderSkin = spark.skins.mobile160.assets.Button_up; downBorderSkin = spark.skins.mobile160.assets.Button_down; //( 中略 ) break; } } }

各DPIに適したデフォルトのスキン外観は、それぞれ下記パッケージに用意されています。

≪SDK folder≫/frameworks/projects/mobiletheme/src/spark/skins/mobile160/assets/ ≪SDK folder≫/frameworks/projects/mobiletheme/src/spark/skins/mobile240/assets/ ≪SDK folder≫/frameworks/projects/mobiletheme/src/spark/skins/mobile320/assets/

次のサンプルは、それぞれの画面密度用に提供しているFXGを直接Viewに貼り付けたものです。原寸で表示させると違いが分かります(サンプル:SkinEachDPISample.fxp)

@media構文を用いた画面密度による振り分け

前項では、スキンクラス内でDPIを検出して外観を変更する方法を紹介しましたが、他にもFlex CSSの@media構文を用いて各DPIや各OSに基づいたスタイルを定義する方法が用意されています。使用できる@madia構文のプロパティは次の2つです。

@madia構文のプロパティ

プロパティ 説明 有効値
application-dpi Flexフレームワークが算出する画面密度の近似値です。 160, 240, 320
os-platform flash.system.Capabilities.versionプロパティの値に相当する文字列です。 "Android", "iOS", "Macintosh", "Windows", "Linux"

また、これらの@madia構文は「and」「not」「,」(カンマ)といった演算子を使用することも可能です(カンマはOR条件演算子です)。

次のサンプルは、モバイル端末のDPIによって、ボタンのラベルの色を変更させるサンプルです(サンプル:MobileMediaQuerySample.fxp)

ソースコード:MobileMediaQuerySample/src/MobileMediaQuerySample.mxml

<?xml version="1.0" encoding="utf-8"?> <s:ViewNavigatorApplication xmlns:fx = "http://ns.adobe.com/mxml/2009" xmlns:s = "library://ns.adobe.com/flex/spark" firstView = "views.MobileMediaQuerySampleHomeView" > <fx:Style> @namespace s "library://ns.adobe.com/flex/spark"; @media (application-dpi: 160) and (os-platform : "Android") { s|Button { color : #990000; } } @media (application-dpi: 240) and (os-platform : "Android") { s|Button { color : #009900; } } </fx:Style> </s:ViewNavigatorApplication>

DPIに基づいたビットマップアセットの選択

通常、ビットマップ画像のアセットは1つの解像度でのみ最適にレンダリングされますが、対モバイル端末のように複数の解像度を対象としたアプリケーションをデザインする場合は、困難を伴う可能性があります。

ここで役に立つのが、新しく採用された spark.utils.MultiDPIBitmapSourceクラスです。このクラスは、Flexフレームワークが算出したDPI値に従って、適切なビットマップを読み込む機能を持ったビットマップのリストです。BitmapImageやImageコンポーネントのsourceプロパティ、Buttonコンポーネントのiconプロパティに使用することできます。

次のサンプルでは、ButtonコンポーネントのiconプロパティにMultiDPIBitmapSourceをセットして、DPIに従って異なる画像を読み込みます。前項のサンプル(MobileMediaQuerySample.fxp)に対して、次のように追記します(サンプル:MultiDPIBitmapSourceSample.fxp)。

MultiDPIBitmapSourceSample/src/views/MultiDPIBitmapSourceSampleHomeView.mxml

<s:Button width="100%" label="DPI Test" iconPlacement="top"> <s:icon> <s:MultiDPIBitmapSource source160dpi = "@Embed('/assets/images/taigaDPI160.png')" source240dpi = "@Embed('/assets/images/taigaDPI240.png')" /> </s:icon> </s:Button>

おわりに

以上がFlexモバイルスキンについての基本的な項目の紹介でした。PC版Flex製AIRアプリケーションと比べて、モバイル版Flexアプリケーションでは、ターゲット端末の解像度や画面密度がそれぞれ異なることを意識し、それらの環境の溝をいかにして埋めていくかを踏まえて設計・開発しなければならないことに気付いたかと思います。

対応するモバイル端末の幅が広ければ広いほど、デザイナーもデベロッパーも従来の倍の労力を割かねばなりませんが、Flexモバイルフレームワークではそういった苦労を幾分か緩和してくれます。

これらのチュートリアルを確認し、Flexモバイルアプリケーションのスキン機構を知ることによって、実際にアプリケーション開発に携わるとき、より現実的な設計を行うことができるでしょう。

関連記事