このマスターシリーズでは、Adobe AIR 2.6で導入されたデスクトップおよびモバイルプラットフォームの新機能について解説します。

本記事では、Adobe AIR 2.6から導入されたデスクトップ関連機能の中から、ネイティブ機能の拡張などについて解説します。

サンプル:AIR26_001_samples

新機能について

今回は、以下の新機能について取り上げます。

  • デスクトップ用に所有されるネイティブウィンドウ
  • デスクトップでのネイティブメニューイベント
  • デスクトップでのネイティブマウスカーソル
  • ビットマップイメージの非同期デコード(モバイル開発でも利用可能)

本記事では触れませんが、他にも「Linux環境でのベクター印刷サポート」や「HTTP接続時のアイドルタイムアウト時間の指定(NetConnectionクラスへのhttpIdleTimeoutプロパティ追加)」などがあります。

名前空間の設定

Adobe AIR 2.6の新機能を利用するには、アプリケーション記述子ファイルのルートタグのxmlns属性を下記のように指定する必要があります。

<application xmlns="http://ns.adobe.com/air/application/2.6">

デスクトップ用に所有されるネイティブウィンドウ

NativeWindowクラスにownerプロパティが追加され、ここに親ウィンドウのインスタンスをセットすることで、子ウィンドウとすることができるようになりました。これにより、複数ウィンドウのZオーダーを個別に制御しなくても、子ウィンドウが常に親ウィンドウの手前に表示されるようになります。NativeWindowクラスでは、コンストラクタ引数において、NativeWindowInitOptionsクラスを用いて一括してオプション指定できますが、こちらにもownerプロパティが追加されています。

また、NativeWindowクラスにはlistOwnedWindowsメソッドが追加され、親ウィンドウが所有する子ウィンドウのリストをVector.<NativeWindow>で取得することができます。子ウィンドウがない場合は空のVector配列が返されます。NativeWindowの親子関係はツリー階層になっており、あるウィンドウを閉じると、連動してそのウィンドウを直接または間接的に親に持つ子ウィンドウ群も同時に閉じます。

以下は、あるWindowedApplication内でNativeWindowInitOptionを用いてNativeWindowの子ウィンドウを作成している例です。

var initOpt:NativeWindowInitOptions = new NativeWindowInitOptions(); initOpt.owner = this.nativeWindow; var childWindow:NativeWindow = new NativeWindow(initOpt); var sprite:Sprite = new ChildWindowContainer(); childWindow.stage.addChild(sprite); childWindow.activate();

ownerプロパティにWindowedApplicationインスタンスのnativeWindowプロパティ値をセットして、activateメソッドで開きます。途中のChildWindowContainerは、子ウィンドウの中身を定義したSpriteのサブクラスです。

ただし、現在のFlex 4.5では、MXとSparkコンポーネント、どちらのWindowクラスもNativeWindowのownerプロパティには対応していません(現存するownerプロパティはFlexのコンポーネントにおいて親コンテナを示すものです)。

サンプル01_NativeWindowでは、SparkコンポーネントのWindowクラスを継承したOwnableWindowクラスを用意し、ownerWindowプロパティで所有ウィンドウを設定できるようにしています。実行すると、子ウィンドウを開くボタンと閉じるボタンがそれぞれのウィンドウ内に配置されます。ウィンドウの親子階層関係によるZオーダー、閉じたときの連動を確認することができます。

デスクトップでのネイティブメニューイベント

NativeMenuクラスにpreparingイベントが追加されました。このイベントは、OSごとに動作の差異があったdisplayingイベントを置き換えるものです。そのため、preparingイベントとdisplayingイベントは、どちらかしかハンドルすることができません。

preparingイベントは、前述の名前空間の指定でAdobe AIRのバージョンを2.6にすると有効になります。preparingイベントを使うことで、メニューが表示される直前、またはキーボードショートカットによる呼び出し直前を捕捉することができるようになります。ショートカット呼び出し時は、その対象メニュー項目が属するNativeMenuクラスおよびNativeMenuItemクラスのすべてに対してpreparingイベントが呼び出されます。

ただし、現在のFlex 4.5では、FlexNativeMenuクラスのmenuShowイベントの内部実装はdisplayingイベントを使用しており、preparingイベントに対応していないためAdobe AIR 2.6で使用する際は注意してください。

ネイティブカーソルのサポート

Flash Player 10.2と同様にOS自体のマウスカーソルに対し、独自のビットマップデータを適用して変更できるようになりました。これにより、従来の内部的なカーソル変更よりも軽量に動作し、ドラッグ時でも「独自カーソルが表示されるのはAdobe AIR内だけ」ということがなくなります。

ネイティブカーソルを使用するには、まずMouseCursorDataクラスのインスタンスを生成して、ビットマップデータをどのようにカーソルとして使うかを設定します。dataプロパティに複数のビットマップデータを持つ配列にセットし、フレームレートを1以上にセットするとアニメーションカーソルになります。

var mouseCursorData:MouseCursorData = new MouseCursorData(); var cursorData:Vector.<BitmapData> = new Vector.<BitmapData>(); …(ここでcursorDataにカーソルのビットマップデータをセット)… mouseCursorData.data = cursorData; mouseCursorData.frameRate = 0;

さらにそのインスタンスをMouseクラスの静的なregisterCursorメソッドを使ってネイティブカーソル名を付けて登録します。解除には同クラスの静的なunregisterCursorメソッドを使います。マウスカーソルを変更するときは、Mouseクラスの静的なcursorプロパティに、登録時に指定したネイティブカーソル名をセットします。

Mouse.registerCursor("custom", mouseCursorData); Mouse.cursor = "custom";

MouseCursorクラスの持つ定数群を使って登録した場合、デフォルトのマウスカーソルは上書きされて登録されます。例えば、MouseCursor.IBEAMをカーソル名に指定して登録すると、Mouse.cursorプロパティを変更せずとも、テキストフィールド上では自動的に「Iビーム」形状のカーソルが表示されるようになります。

このようにネイティブカーソルは、局所的なカーソル変更や、アプリケーション全体に対してそれぞれの役割に応じたカーソル変更もできるため、より優れたUIデザインを実現できます。

サンプル01_NativeMouseCursorでは、通常カーソルの切り替えと「Iビーム」形状のカーソルの切り替え動作を確認することができます。星が回転するカスタムカーソルの生成は、StarCursorFactoryクラス内で行っています。なお、アニメーションカーソルとして用意したSWFファイルを、直接MouseCursorDataクラスのインスタンスにすることはできません。フレームごとにイメージを用意して、実行時にビットマップデータをVector化してセットするとよいでしょう。

ビットマップイメージの非同期デコード

LoaderContextクラスに新しくimageDecodingPolicyプロパティが追加され、ビットマップイメージのデコード方法を指定できるようになりました。従来と同様の動作をするON_DEMANDと、ビットマップのデコートまでを非同期にするON_LOADが用意されています。ON_DEMANDとON_LOADの名称だとわかりづらいですが、従来のLoaderクラスでloadメソッドからcompleteイベントが発生するまでの非同期処理にどこまで含まれるかが異なります。

ON_DEMANDでは、イメージのソースからバイナリデータの読み込みまでを非同期処理で行い、バイナリデータをデコードしてビットマップデータにしてレンダリングするまでを同期処理で行います。同期処理というのはAdobe AIR(Flash Player)のシングルスレッド上で処理されるということです。

一方ON_LOADは、イメージのソースからバイナリデータを読み込み、バイナリデータをデコードするまでを非同期処理で行い、ビットマップデータをレンダリングするのは同期処理で行います。つまり、非同期でJPEGやPNGといったバイナリデータをビットマップするデコード処理をバックグラウンドに移すことができます。例えば、アニメーションのようなプログラムでは、重いデコード処理の割り込みによって描画が固まる問題を回避できるメリットがON_LOADにはあります。デメリットとしてはビットマップデータにして保持するので、使い方によってはピーク時のメモリ消費量が増大する可能性があります。

以下は、ON_DEMANDでイメージをロードして、Sparkコンポーネント上に追加する例です。

var loaderContext:LoaderContext = new LoaderContext(); loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_DEMAND; var loader = new Loader(); var req:URLRequest = new URLRequest("http://www.example.com/huge.jpg"); loader.load(req, loaderContext); var uic:UIComponent = new UIComponent(); uic.addChild(loader); addElement(uic);

おわりに

Adobe AIR 2.6から導入されたデスクトップ向けの新機能について紹介しました。よりネイティブアプリケーションに近い動作を実現および実装しやすくなります。なお、Flex 4.5 SDKでは、ネイティブウィンドウ/ネイティブメニューの実装がまだ追いついていないため、今後のバージョンでの機能フォローを確認して使うようにしてください。