NTTドコモR&Dの技術ブログです。

Android XRのViewを簡単に実装する方法

※ 本記事は 2026/3/31 以前にNTTコノキューにて記載した記事になります

0. はじめに

この記事はNTTコノキュー アドベントカレンダー2025の記事です。

こんにちは、NTTコノキューの佐々木です。

今回は、Android XRに対応したViewの作成をなるべく簡単に実装する方法についてご紹介させていただきます。

本記事は、普通のAndroidアプリなら実装できるエンジニアに向けての記事となります。 既存のViewの構成に少しだけ手を入れてAndroidXRでも使えるViewが作成できるようになることを目指します。

1. 2つのモードへの理解

AndroidXRのViewを作成する上で常に意識しなければならないのが、HomeSpaceとFullSpaceという2つの表示モードです。

それぞれのモードを簡単に説明します。 詳細な説明については公式ドキュメントをご参照ください。

HomeSpaceモード

1枚のViewをそのまま表示するモードです。

アプリ開発者視点ではほぼ気にする必要がないモードで、Androidタブレットの横向き状態の画面想定してViewを作ればそのまま使用できます。

画像には三つのアイコンが並んだTopメニューのようなものが出ていますが、これはOS側が自動で表示しているものなので、HomeSpaceモードだと実装不要で表示されるものです

HomeSpaceモードは今まで通りの開発でViewの作成ができると思います。

FullSpaceモード

1つのViewから任意のパーツに分解して表示するモードです。

個々のパーツを拡大縮小等ができるようになり、XRのViewと言えばFullSpaceモードで表示するViewであると言えるでしょう。

アプリ開発側の視点で言えばFullSpaceで利用できるViewを用いる必要があったり、今までのViewとは異なり1つのViewの中にバラバラに動かせるパーツを用意する必要があったりとします。

AndroidXRの開発で重要なのはこのFullSpaceモードで表示するViewの作成と言えるでしょう。

2つのモードで表示するView

上記の2つのモードはAndroidXR上で切り替えが可能です。 マテリアルデザインのドキュメントにある動画のようにモードが切り替えられると思って下さい。

そのためどちらのモードでもアプリが表示される可能性があり、どちらのモードでも表示できることが望ましいのは言うまでもありません。

つまり、AndroidXRのViewは2つのモードで表示することを意識して開発する必要があります。

それぞれのモード用のViewを作成するのが一番手っ取り早い手段ですが、その場合1つの機能を作るのに2つのViewを作成する必要があり、開発工数が増加してしまいます。

可能な限り1つのViewで2つのモードで利用できるようにしたいというのが、開発者の心情でしょう。

そこで本記事で1つのViewでHomeSpaceモード用とFullSpaceモード用の表示ができるようにするテクニックを紹介します。

2. EnableXrComponentOverrides

「EnableXrComponentOverrides」は「androidx.xr.compose.material3」の「1.0.0-alpha12」でリリースされたComposableです。 「1.0.0-alpha12」は2025/10/22にリリースされたライブラリですので、執筆時点では1ヶ月と少し前にリリースされたばかりのComposableになります。

公式ドキュメントにはこうあります。

Clients can wrap their Compose hierarchy in this function to dynamically enable XR components when in the proper environment.

Google翻訳後
クライアントはComposableをこの関数でラップすることで適切な環境にあるときに XR コンポーネントを動的に有効にすることができます。

つまり、既存のViewを「EnableXrComponentOverrides」で囲えば、FullSpaceモードで自動的にモードにあった表示に変えられるのでは?と考え色々と試してみました。

実装としては以下のような形になります。


EnableXrComponentOverrides {
    // ここに既存のView(Composable)を丸々入れる
}

先に結論から言うと上手く行きませんでした。

なので、2025/12/03時点で実際に使える手段をすぐ見たいと言う方は「3. Orbitor」まで飛ばして読んでください。

ただ「EnableXrComponentOverrides」はリリースされたばかりのComposableですので、これから改善していく可能性が高いです。 ライブラリのバージョンアップがあった際に、この記事に書いてある内容を加味しつつ試してみれば、意外とどうにかなっているかもしれませんので、参考程度に読んでいただければと思います。

XR向けではない既存のViewを対象にした場合

今まで利用してきたColumnやRow等のViewを「EnableXrComponentOverrides」で囲った場合を試してみました。

こちらは特に効果はなく、HomeSpaceモードで表示したViewがそのままFullSpaceモードでも表示されました。

なおHomeSpaceモードで表示したViewのままFullSpaceモードに表示する場合は、「EnableXrComponentOverrides」で囲わなくても同じ動きになるので、「EnableXrComponentOverrides」は使っても使わなくても同じ表示になります。

今の所、既存のViewを「EnableXrComponentOverrides」で囲った場合に有意な効果は見られませんでした。

XrComponentOverride内で定義されたViewを対象にした場合

「XrComponentOverride」は「EnableXrComponentOverrides」で使用されているclassで、いくつかのComposableの名前が定義されています。

EnableXrComponentOverridesの実装を見ると「XrComponentOverride」で定義された名前のViewは特別に変換する処理が記述されており、同時に「EnableXrComponentOverrides」の引数で、あえて変換対象から外すということができます。

そのため、「XrComponentOverride」で定義された名前のViewを使ったらどうなるかを試してみました。

使ったのはNavigableSupportingPaneScaffoldで、「XrComponentOverride」では「ThreePaneScaffold」で定義されています。

HomeSpaceモードでは以下のように表示されました。

「EnableXrComponentOverrides」が動作するのはFullSpaceモードですので、このViewを元にFullSpaceモードでViewが変換されて表示されます。

そして、上記ViewをFullSpaceモードで動かすと以下のようになります。

何故かNavigableSupportingPaneScaffold以外のViewが消え、NavigableSupportingPaneScaffoldが画面いっぱいまで拡大されて表示されました。

これではFullSpaceモードのViewとして十分とは言えません。

また、他にも「XrComponentOverride」内で定義されているViewを色々試してみましたが、想定したような綺麗なViewにならなかったです。もしかしたら、実装に際して何がしかの工夫が必要なのかもしれません。

少なくとも単純に「EnableXrComponentOverrides」を囲うだけではFullScreen向けのViewはできないようです。

残念ですが、「EnableXrComponentOverrides」を使って簡単にFullScreenモード用のViewを用意することは困難と判断しました。

3. Orbiter

さて前章で「EnableXrComponentOverrides」で簡単にFullScreenモードのViewを作ることは難しそうという結論になりました。

そこで、本記事ではOrbiterを使うことをお勧めします。

Orbiterとは?

突然出てきたOrbiterと言う言葉ですが、ユーザーにメインで見せたいコンテンツに紐づく小さなViewだと思って下さい。

詳細はAndroidXR開発向けの公式ドキュメントに記載されているので、詳しく知りたい方はそちらを参照して下さい。

本記事で紹介するOrbiterはComposableですが、HomeSpaceモードでは何もしません。 OrbiterというComposableは存在しない体でViewが表示されます。

言葉だけだと分かりにくいので実際に画像と共に説明します。

まず、基準となるHomeSpaceモードのViewは前章にもあった以下になります。

上記の時点ですでにOrbiterは実装されているのですが、HomeSpaceモードでは何もしないので、特に既存のViewと差異はありません。

このViewをFullSpaceモードで表示すると以下のような表示になります。

HomeSpaceモードでは内側にあったメニューバーとタイトルバーが、FullSpaceモードでは詳細&リストのViewの外側に浮くような表示になっています。

このメニューバーとタイトルバーがOrbiterで囲ったViewになります。

上記の画像を見れば分かるように、Orbiterを使うだけで最低限のXRの体裁を整えたViewになったと言えるのではないでしょうか?

実装方法

それでは実際の実装方法についてですが、本記事の主題は「簡単にXR(FullSpaceモード)用の表示ができる」なので、実装方法も単純です。

それは、「外出ししたいViewをOrbiterで囲う」ただこれだけです。 具体的には以下のような実装になります。


Orbiter(
    position = ContentEdge.Start,
    alignment = Alignment.CenterVertically,
    offsetType = OrbiterOffsetType.Overlap,
    offset = (-16).dp,
    shape = SpatialRoundedCornerShape(
        CornerSize(percent = 100)
    )
) {
    // ここに画面左側に表示するCompozableを入れる形で実装
}

Orbiter(
    position = ContentEdge.Top,
    alignment = Alignment.CenterHorizontally,
    offsetType = OrbiterOffsetType.Overlap,
    offset = (-16).dp,
) {
    // ここに画面上部に表示するCompozableを入れる形で実装
}

それぞれのパラメーターについて説明しましょう

position

Orbiterで囲ったViewをどこに表示するかの設定になり、Orbiterで唯一の必須パラメータになります。ContentEdgeで定義された4つのパラメータの内1つを設定します。

4つのパラメータはそれぞれ以下のようになります。

  • ContentEdge.Top

  • ContentEdge.Bottom

  • ContentEdge.Start

ContentEdge.End

それぞれ、OrbiterのViewが上、下、左、右に表示されるようになります。

なお、コードの上でのOrbiterの見た目は変わらないのですが、positionを設定することでOrbiterは2つの種類に分かれます。 TopまたはBottomを設定した場合はHorizontal。 StartまたはEndを設定した場合はVerticalとなります。 上記の違いはそのままalignmentで指定できるパラメータの違いになります。 (HorizontalとVerticalが逆なのではと思いますが、ContentEdge内では上記のように定義されています)

positionとalignmentを指定してエラーになる場合、設定したpositionでは使えないalignmentを指定していないかを確認すると良いでしょう。

alignment

Orbiter内のViewをどちらに寄せるかの設定になります。 前述していますが、設定したpositionによってalignmentに設定できるパラメータが変わってきます。

positionにTopまたはBottomを設定した場合に設定できるのは以下になります。

  • Alignment.Start

  • Alignment.CenterHorizontally

  • Alignment.End

それぞれ、左寄せ、中央寄せ、右寄せになります。

positionにStartまたはEndを指定した場合に設定できるのは以下になります。

  • Alignment.Top

  • Alignment.CenterVertically

  • Alignment.Bottom

それぞれ、上寄せ、中央寄せ、下寄せになります。

offsetType

Orbiterをメインのコンテンツに対してどのように配置するかを設定できます。

言葉だけでは分かりづらいので、実際の配置は画像で説明しますが、まずは設定できるパラメータの一覧を説明します。

以下がそのパラメータになります。

  • OrbiterOffsetType.OuterEdge

  • OrbiterOffsetType.InnerEdge

  • OrbiterOffsetType.Overlap

それではそれぞれのパラメータを設定した場合の配置を「position=ContentEdge.Top」のOrbiterを例にして画像で説明します。

OrbiterOffsetType.OuterEdgeの場合

OrbiterOffsetType.InnerEdgeの場合

OrbiterOffsetType.Overlapの場合

なお、今回はわかりやすくするために、Orbiterの位置を調整した画像を表示しています。 実際にはメインコンテンツに自動でpaddingが設定されているらしく、デフォルトでは微妙にズレた位置に表示されてしまいます。

位置の細かな微調整は次のoffsetと言うパラメータで行うことができるので、そちらでコントロールするといいです。

offset

Orbiterの表示位置を微調整するパラメータでDPで指定します。

ただし、使用の際には少し注意が必要でoffsetTypeがOverlapかそれ以外かで動きが異なります。

まずはoffsetTypeがOverlapの場合ですが、設定する数値を大きくすればOrbiterの表示位置はメインコンテンツに近づくように移動します。

逆にoffsetTypeがOverlap以外の場合だと、設定する数値を大きくすればOrbiterの表示位置はメインコンテンツから離れるように移動します。

少々ややこしいですが、使用の際には注意しましょう。

また、設定するDPはマイナスの値も可能です。マイナスの値を設定すれば上記とは逆の動きをしますので、上手く使ってOrbiterを望んだ位置に移動させましょう。

shape

Orbiterで囲ったViewの形を設定します。角丸等でOrbiterを表示したい場合に使用します。

「SpatialShape」を継承したクラスを設定できますが、今回の実装例のように「SpatialRoundedCornerShape」を使って設定することになると思います。

また、今回の実装例ですとメニューバーはshapeを指定していますが、タイトルバーはshapeを設定していません。 これは、元々タイトルバー自体が角丸になるように実装しているため、shapeで変形する必要がないためです。

shapeは中に設定したViewの形をOrbiterとして表示する際に変形したい場合に使用すると良いでしょう。

その他のパラメータ

上記で紹介したもの以外にもOrbiterには設定できるパラメータがありますが、基本的にはデフォルトの設定のままで十分です。

4. まとめ

なるべく簡単に既存のViewをXR用(FullScreenモード用)のViewにする方法を説明しました。

Orbiterを使った方法はHomeSpace用のViewを1つ作るだけで、FullSpaceモードでも同じViewを使用してFullSpaceモード用の表示を実現できるようになるため、AndroidXRのViewを作る入門としておすすめです。

また、「EnableXrComponentOverrides」は現段階では上手い活用ができませんでしたが、まだまだリリースされたばかりのComposableですので、ライブラリのアップデートや今後の調査で具体的な利用方法が分かるようになるかもしれません。 引き続きチェックできればと思います。

まずはOrbiterを使ってAndroidXRのViewを作るのはいかがでしょうか。