アプリでタイルの提供を開始するには、アプリの build.gradle
ファイルに次の依存関係を追加します。
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.5.0" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.3.0" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.3.0" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.3.0" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.5.0" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.5.0") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.3.0") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.3.0") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.3.0") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.5.0") }
主な概念
タイルは Android アプリと同じ方法で構築されず、異なるコンセプトを利用します。
- レイアウト テンプレート: ディスプレイ上の視覚要素の全体的な配置を定義します。これは
primaryLayout()
関数によって実現されます。 - レイアウト要素: ボタンやカードなどの個々のグラフィック要素、または列やbuttonGroupなどを使用してグループ化された複数の要素を表します。これらはレイアウト テンプレート内に埋め込まれています。
- リソース:
ResourceBuilders.Resources
オブジェクトは、レイアウトのレンダリングに必要な Android リソース(画像)の Key-Value ペアのマップとバージョンで構成されます。 - タイムライン:
TimelineBuilders.Timeline
オブジェクトは、1 つ以上のレイアウト オブジェクトのインスタンスのリストです。レンダラがレイアウト オブジェクトを切り替えるタイミング(特定の時間にレイアウトの表示を停止するなど)を示すために、さまざまなメカニズムと式を指定できます。 - 状態: タイルとアプリの間で渡される
StateBuilders.State
型のデータ構造。2 つのコンポーネントが互いに通信できるようにします。たとえば、タイル上のボタンがタップされた場合、状態にはボタンの ID が保持されます。マップを使用してデータ型を交換することもできます。 - タイル: タイルを表す
TileBuilders.Tile
オブジェクト。タイムライン、リソース バージョン ID、更新間隔、状態で構成されます。 - Protolayout: この用語は、さまざまなタイル関連クラスの名前に現れ、さまざまな Wear OS サーフェスで使用されるグラフィック ライブラリである Wear OS Protolayout ライブラリを指します。
タイルを作成する
アプリでタイルを表示するには、TileService
タイプのサービスを実装して、マニフェストに登録します。このことから、システムは onTileRequest()
の呼び出し時に必要なタイルをリクエストし、onTileResourcesRequest()
の呼び出し時にリソースをリクエストします。
class MyTileService : TileService() { override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( materialScope(this, requestParams.deviceConfiguration) { primaryLayout( mainSlot = { text("Hello, World!".layoutString, typography = BODY_LARGE) } ) } ) ) .build() ) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture( Resources.Builder().setVersion(RESOURCES_VERSION).build() ) }
次に、AndroidManifest.xml
ファイルの <application>
タグ内にサービスを追加します。
<service android:name=".snippets.m3.tile.MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@mipmap/ic_launcher" android:exported="true" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service>
権限とインテント フィルタにより、このサービスがタイル プロバイダとして登録されます。
ユーザーがスマートフォンまたはスマートウォッチでタイルを設定すると、アイコン、ラベル、説明、プレビュー リソースが表示されます。プレビュー リソースは Android の標準リソース修飾子をすべてサポートしているため、画面サイズやデバイスの言語などの要素に応じてプレビューを変化させることができます。その他の推奨事項については、プレビューのチェックリストをご覧ください。
アプリをデプロイし、タイルをタイル カルーセルに追加します(タイルをプレビューするデベロッパー向けのより簡単な方法もありますが、今のところは手動で行ってください)。

完全な例については、GitHub のコードサンプルまたは codelab をご覧ください。
タイルの UI を作成する
Material 3 の表現力豊かな UI 要素は、Kotlin のタイプセーフ ビルダー パターンを活用した構造化されたアプローチを使用して作成されます。
レイアウト
効果的でレスポンシブなタイル レイアウトの作成の背後にある設計原則については、タイルの一般的なレイアウトをご覧ください。
レイアウトを作成する手順は次のとおりです。
マテリアル デザイン スコープを開始する: 必要な
context
とdeviceConfiguration
を指定して、materialScope()
関数を呼び出します。allowDynamicTheme
やdefaultColorScheme
などのオプション パラメータを含めることができます。allowDynamicTheme
はデフォルトでtrue
であり、defaultColorScheme
は、動的カラーが利用できない場合(ユーザーが機能をオフにしている場合、デバイスでサポートされていない場合、allowDynamicTheme
がfalse
の場合など)に使用されるColorScheme
を表します。スコープ内で UI を構築する: 特定の Tile レイアウトのすべての UI コンポーネントは、単一のトップレベルの materialScope() 呼び出しのラムダ内で定義する必要があります。
primaryLayout()
やtextEdgeButton()
などのコンポーネント関数は、MaterialScope
の拡張関数であり、このレシーバ スコープで呼び出された場合にのみ使用できます。materialScope( context = context, deviceConfiguration = requestParams.deviceConfiguration, // requestParams is passed to onTileRequest defaultColorScheme = myFallbackColorScheme ) { // inside the MaterialScope, you can call functions like primaryLayout() primaryLayout( titleSlot = { text(text = "Title".layoutString) }, mainSlot = { text(text = "Main Content".layoutString) }, bottomSlot = { textEdgeButton(text = "Action".layoutString) } ) }
スロット
M3 では、タイル レイアウトに Compose にインスピレーションを得たアプローチが採用されており、3 つの異なるスロットが使用されています。上から順に次のとおりです。
titleSlot
。通常はメインのタイトルまたは見出しに使用します。- コア コンテンツの
mainSlot
。 bottomSlot
: アクションや補足情報によく使用されます。エッジボタンもここに表示されます。

各スロットの内容は次のとおりです。
titleSlot
(省略可): 通常は、text()
によって生成された数語です。mainSlot
(必須): 行、列、ボタン グループなどの構造に整理されたコンポーネント。これらのコンポーネントは、互いに再帰的に埋め込むこともできます。たとえば、列に行を含めることができます。bottomSlot
(省略可): 通常は、エッジに沿ったボタンまたはテキスト ラベルのいずれかで埋められます。
タイルはスクロールできないため、ページング、スクロール、長いコンテンツ リストの処理を行うコンポーネントはありません。フォントサイズが大きくなったり、翻訳によってテキストが長くなったりしても、コンテンツが読めるようにしてください。
UI コンポーネント
protolayout-material3
ライブラリには、マテリアル 3 の表現仕様とユーザー インターフェースの推奨事項に沿って設計されたコンポーネントが多数用意されています。
ボタン
ボタンは主に行動を促す目的で使用されます。特定の操作をトリガーするために使用されます。各ボタンのコンテンツ(アイコンや短いテキストなど)は、アクションを識別します。
- textButton(): (短い)テキスト コンテンツ用のスロットが 1 つあるボタン
- iconButton(): アイコンを表す単一のスロットを持つボタン
- avatarButton(): 縦に積み重ねられたラベルとセカンダリ ラベルを表すコンテンツと、その横の画像(アバター)を取得するためのスロットを最大 3 つ提供する、ピル型のボタン
- imageButton(): クリック可能な画像ボタン。追加のスロットは提供されず、画像のみ(例: backgroundImage を背景として使用)
- compactButton(): アイコンとテキストが横に並んだコンテンツを水平方向に積み重ねて取得するためのスロットを最大 2 つ提供するコンパクト ボタン
- button(): 縦に積み重ねられたラベルとセカンダリ ラベルを表すコンテンツと、その横のアイコンを取得するための最大 3 つのスロットを提供するピル型のボタン
エッジボタン
エッジボタンは、スマートウォッチの丸い画面の下部に固定された、全幅の特殊なボタンです。現在のタイル画面から実行する最も重要なアクションを表します。
- iconEdgeButton(): アイコンまたは同様の丸い小さなコンテンツを取得するための単一のスロットを提供するエッジボタン
- textEdgeButton(): テキストや同様に長く幅の広いコンテンツを取得するための単一のスロットを提供するエッジボタン
カード
カードは主に情報提供を目的としています。関連する構造化データのコレクションを表示します。インタラクティブ カードを作成できますが、通常は情報の概要が表示され、ユーザーがタップすると詳細が表示されたり、関連するアクションを実行したりできます。
- titleCard(): 1 ~ 3 個のスロットを提供するタイトルカード(通常はテキストベース)
- appCard(): 最大 5 つのスロットを提供するアプリカード。通常はテキストベース
- textDataCard(): 通常はテキストまたは数字ベースの、縦に積み重ねられた最大 3 つのスロットを提供するデータカード
- iconDataCard(): 通常はテキストまたは数字ベースで、アイコン付きの縦に積み重ねられた最大 3 つのスロットを提供するデータカード
- graphicDataCard(): 進捗インジケーターなどのグラフィック データ用のスロットと、通常はテキストの説明用の縦に積み重ねられた最大 2 つのスロットを提供するグラフィック データカード
進行状況インジケーター
- circularProgressIndicator(): 放射状の要素を使用して目標に対する進捗状況を示します
- segmentedCircularProgressIndicator(): 異なるステージの放射状要素を使用して目標に対する進捗状況を示します
レイアウト要素のグループ化
- buttonGroup(): 子を横方向に並べて配置するコンポーネント レイアウト
- primaryLayout(): 推奨される M3 レイアウト スタイルを表す全画面レイアウト。レスポンシブで、要素の配置を処理し、推奨されるマージンとパディングが適用される
テーマ設定
マテリアル 3 Expressive では、カラーシステムは 29 個の標準カラーロールで定義され、プライマリ、セカンダリ、ターシャリ、エラー、サーフェス、アウトラインの 6 つのグループに分類されます。

ColorScheme
は、これらの 29 個のロールをそれぞれ対応する色にマッピングします。また、MaterialScope
の一部であり、コンポーネントは MaterialScope
内で作成する必要があるため、コンポーネントはスキームから自動的に色を取得します。このアプローチにより、すべての UI 要素がマテリアル デザイン基準に自動的に準拠します。
ユーザーが、ブランドカラーを反映したカラーパターンなど、デベロッパーが定義したカラーパターンと、システムが提供するカラーパターン(ユーザーの現在のウォッチフェイスから派生したカラーパターン、またはユーザーが選択したカラーパターン)のいずれかを選択できるようにするには、次のように MaterialScope
を初期化します。
val myColorScheme =
ColorScheme(
primary = ...
onPrimary = ...
// 27 more
)
materialScope(
defaultColorScheme = myColorScheme
) {
// If the user selects "no theme" in settings, myColorScheme is used.
// Otherwise, the system-provided theme is used.
}
タイルを強制的に指定したカラースキームで表示するには、allowDynamicTheme
を false
に設定して、ダイナミック テーマのサポートを無効にします。
materialScope(
allowDynamicTheme = false,
defaultColorScheme = myColorScheme
) {
// myColorScheme is *always* used.
}
色
各コンポーネントは、ColorScheme
で定義された 29 個のカラーロールのサブセットを使用します。たとえば、ボタンは最大 4 色を使用します。デフォルトでは、アクティブな ColorScheme
の「プライマリ」グループから取得されます。
ButtonColors コンポーネント トークン |
ColorScheme ロール |
---|---|
containerColor | primary |
iconColor | onPrimary |
labelColor | onPrimary |
secondaryLabelColor | onPrimary(不透明度 0.8) |
Wear OS のデザインに色を適用する際の詳細なガイダンスについては、色のデザイン ガイドをご覧ください。
特定の UI 要素では、デフォルトのカラートークンから逸脱する必要がある場合があります。たとえば、textEdgeButton
を「プライマリ」ではなく「セカンダリ」または「ターシャリ」グループの色を使用して、目立たせ、コントラストを強くすることができます。
コンポーネントの色は、次の方法でカスタマイズできます。
事前定義された色にヘルパー関数を使用します。
filledTonalButtonColors()
などのヘルパー関数を使用して、マテリアル 3 エクスプレッシブの標準ボタン スタイルを適用します。これらの関数は、塗りつぶし、トーン、アウトラインなどの一般的なスタイルをMaterialScope
内のアクティブなColorScheme
の適切なロールにマッピングする、事前構成済みのButtonColors
インスタンスを作成します。これにより、一般的なボタンタイプごとに色を手動で定義することなく、一貫したスタイルを適用できます。textEdgeButton( colors = filledButtonColors() // default /* OR colors = filledTonalButtonColors() */ /* OR colors = filledVariantButtonColors() */ // ... other parameters )
カードの場合は、同等の
filledCardColors()
ファミリーの関数を使用します。1 つまたは 2 つのトークンのみを変更する必要がある場合は、ヘルパー関数によって返された
ButtonColors
オブジェクトのcopy()
メソッドを使用して、オブジェクトを変更することもできます。textEdgeButton( colors = filledButtonColors() .copy( containerColor = colorScheme.tertiary, labelColor = colorScheme.onTertiary ) // ... other parameters )
置換色のロールを明示的に指定します。独自の
ButtonColors
オブジェクトを作成して、コンポーネントに渡します。カードの場合は、同等のCardColors
オブジェクトを使用します。textEdgeButton( colors = ButtonColors( // the materialScope makes colorScheme available containerColor = colorScheme.secondary, iconColor = colorScheme.secondaryDim, labelColor = colorScheme.onSecondary, secondaryLabelColor = colorScheme.onSecondary ) // ... other parameters )
固定色を指定します(注意して使用してください)。一般的には、セマンティック ロール(
colorScheme.primary
)を使用する代わりに、直接色値を指定することもできます。このアプローチは、テーマが動的に変化する場合など、全体的なテーマとの不整合につながる可能性があるため、慎重に使用する必要があります。textEdgeButton( colors = filledButtonColors().copy( containerColor = android.graphics.Color.RED.argb, // Using named colors labelColor = 0xFFFFFF00.argb // Using a hex code for yellow ) // ... other parameters )
タイポグラフィ
デザインでタイポグラフィを効果的に使用する方法について詳しくは、タイポグラフィ デザイン ガイドをご覧ください。
Wear OS プラットフォーム全体で視覚的な一貫性を保ち、パフォーマンスを最適化するため、タイル上のすべてのテキストはシステム提供のフォントを使用してレンダリングされます。つまり、タイルはカスタム書体をサポートしていません。Wear OS 6 以降では、これは OEM 固有のフォントです。ほとんどの場合、可変フォントが使用され、より表現力豊かなエクスペリエンスと、よりきめ細かい制御が可能になります。
テキスト スタイルを作成するには、通常、text()
メソッドとタイポグラフィ定数を組み合わせて使用します。このコンポーネントを使用すると、Material 3 Expressive で事前定義されたタイポグラフィ ロールを活用できます。これにより、読みやすさと階層構造に関する確立されたタイポグラフィのベスト プラクティスに沿ってタイルを作成できます。このライブラリには、BODY_MEDIUM などの18 個のセマンティック タイポグラフィ定数が用意されています。これらの定数は、サイズ以外のフォント軸にも影響します。
text(
text = "Hello, World!".layoutString,
typography = BODY_MEDIUM,
)
さらに細かく制御するには、追加の設定を指定できます。Wear OS 6 以降では、可変フォントが使用される可能性が高く、斜体、太さ、幅、丸みの軸に沿って変更できます。これらの軸は、settings
パラメータを使用して制御できます。
text(
text = "Hello, World".layoutString,
italic = true,
// Use elements defined in androidx.wear.protolayout.LayoutElementBuilders.FontSetting
settings =
listOf(weight(500), width(100F), roundness(100)),
)
最後に、サイズや文字間隔を制御する必要がある場合(推奨されません)は、text() の代わりに basicText() を使用し、fontStyle() を使用して fontStyle
プロパティの値を構築します。
図形と余白
ほとんどのコンポーネントの角の丸みは、shape
プロパティを使用して変更できます。値は MaterialScope
プロパティ shapes
から取得されます。
textButton(
height = expand(),
width = expand(),
shape = shapes.medium, // OR another value like shapes.full
colors = filledVariantButtonColors(),
labelContent = { text("Hello, World!".layoutString) },
)
コンポーネントの形状を変更した後、ディスプレイの端の周囲のスペースが多すぎる、または少なすぎると感じた場合は、primaryLayout()
の margin
パラメータを使用してマージンを調整します。
primaryLayout(
mainSlot = {
textButton(
shape = shapes.small,
/* ... */
)
},
// margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins
margins = MAX_PRIMARY_LAYOUT_MARGIN,
)
円弧
サポートされている Arc
コンテナの子は次のとおりです。
ArcLine
: 円弧の周りに曲線をレンダリングします。ArcText
: 円弧の中に曲線テキストをレンダリングします。ArcAdapter
: 円弧の中に基本的なレイアウト要素をレンダリングし、円弧の接線上に描画します。
詳細については、それぞれの要素のリファレンス ドキュメントをご覧ください。
修飾子
利用可能なすべてのレイアウト要素に、必要に応じて修飾子を適用できます。修飾子は以下の目的で使用します。
- レイアウトの外観を変更する: たとえば、レイアウト要素に背景、枠線、パディングを追加します。
- レイアウトに関するメタデータを追加する: たとえば、スクリーン リーダーで使用するセマンティクス修飾子をレイアウト要素に追加します。
- 機能を追加する: たとえば、レイアウト要素にクリック可能な修飾子を追加して、タイルをインタラクティブにします。詳しくは、タイルを操作するをご覧ください。
たとえば、次のコードサンプルに示すように、Image
のデフォルトの外観とメタデータをカスタマイズできます。
Kotlin
private fun myImage(): LayoutElement = Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(Modifiers.Builder() .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Java
private LayoutElement myImage() { return new Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(new Modifiers.Builder() .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(new Padding.Builder().setStart(dp(12f)).build()) .setSemantics(new Semantics.Builder() .setContentDescription("Image description") .build() ).build() ).build(); }
Spannable
Spannable
は、テキストと同様に要素をレイアウトする特別なタイプのコンテナです。大きなテキスト ブロック内の 1 つの部分文字列だけに別のスタイルを適用する場合に便利です。これは Text
要素では不可能です。
Spannable
コンテナは Span
の子で満たされます。その他の子やネストされた Spannable
インスタンスは使用できません。
Span
の子には、次の 2 種類があります。
たとえば、次のコードサンプルに示すように、「Hello world」タイルの「world」を斜体にし、単語の間に画像を挿入できます。
Kotlin
private fun mySpannable(): LayoutElement = Spannable.Builder() .addSpan(SpanText.Builder() .setText("Hello ") .build() ) .addSpan(SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(SpanText.Builder() .setText("world") .setFontStyle(FontStyle.Builder() .setItalic(true) .build()) .build() ).build()
Java
private LayoutElement mySpannable() { return new Spannable.Builder() .addSpan(new SpanText.Builder() .setText("Hello ") .build() ) .addSpan(new SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(new SpanText.Builder() .setText("world") .setFontStyle(newFontStyle.Builder() .setItalic(true) .build()) .build() ).build(); }
リソースを扱う
タイルはアプリのリソースにアクセスできません。これは、Android 画像 ID を Image
レイアウト要素に渡して解決することができないことを意味します。代わりに、onTileResourcesRequest()
メソッドをオーバーライドし、リソースを手動で指定します。
onTileResourcesRequest()
メソッド内で画像を指定する方法には次の 2 つがあります。
setAndroidResourceByResId()
を使用して、ドローアブル リソースを指定する。setInlineResource()
を使用して、動的な画像をByteArray
として指定する。
Kotlin
override fun onTileResourcesRequest( requestParams: ResourcesRequest ) = Futures.immediateFuture( Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", ImageResource.Builder() .setAndroidResourceByResId(AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", ImageResource.Builder() .setInlineResource(InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() )
Java
@Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture( new Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", new ImageResource.Builder() .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", new ImageResource.Builder() .setInlineResource(new InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() ); }
タイルのプレビュー画像のチェックリスト
システムは、Android アプリのマニフェストで参照されているタイルのプレビュー画像を、新しいタイルを追加するためのタイル カルーセル エディタに表示します。このエディタは、Wear OS デバイスとスマートフォンのスマートウォッチ コンパニオン アプリの両方に表示されます。
ユーザーがこのプレビュー画像を最大限に活用できるように、タイルの次の詳細情報を確認してください。
- 最新のデザインを反映しています。プレビューには、タイルの最新のデザインが正確に反映されている必要があります。
- 推奨されるディメンションを使用する。最適な表示品質と優れたユーザー エクスペリエンスを提供するには、プレビュー画像のサイズを 400 ピクセル × 400 ピクセルにする必要があります。
- 静的なカラーテーマを使用します。動的なものではなく、タイルの静的なカラーテーマを使用します。
- アプリアイコンが含まれます。アプリのアイコンがプレビュー画像の上部に表示されていることを確認します。
- 読み込み済み/ログイン済みの状態を表示します。プレビューには、完全に機能する「読み込み済み」または「ログイン済み」の状態が表示されるようにし、空のコンテンツやプレースホルダ コンテンツは避けてください。
- カスタマイズにリソース解決ルールを活用します(省略可)。Android のリソース解決ルールを使用して、デバイスのディスプレイ サイズ、言語、ロケール設定に一致するプレビューを提供することを検討してください。これは、タイルがデバイスによって異なる場合に特に便利です。