タイルのスタートガイド

アプリでタイルの提供を開始するには、アプリの build.gradle ファイルに次の依存関係を追加します。

Groovy

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.5.0-alpha04"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.3.0-alpha04"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.3.0-alpha04"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0-alpha04"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.5.0-alpha04"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.5.0-alpha04")

    // Use to utilize standard components and layouts in your tiles
    implementation("androidx.wear.protolayout:protolayout:1.3.0-alpha04")

    // Use to utilize components and layouts with Material Design in your tiles
    implementation("androidx.wear.protolayout:protolayout-material:1.3.0-alpha04")

    // Use to include dynamic expressions in your tiles
    implementation("androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04")

    // Use to preview wear tiles in your own app
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0-alpha04")

    // Use to fetch tiles from a tile provider in your tests
    testImplementation("androidx.wear.tiles:tiles-testing:1.5.0-alpha04")
}

タイルを作成する

アプリでタイルを表示するには、次のコードサンプルに示すように、TileService を拡張するクラスを作成してメソッドを実装します。

class MyTileService : TileService() {

    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setTileTimeline(
                    Timeline.fromLayoutElement(
                        Text.Builder(this, "Hello World!")
                            .setTypography(Typography.TYPOGRAPHY_BODY1)
                            .setColor(argb(0xFFFFFFFF.toInt()))
                            .build()
                    )
                )
                .build()
        )

    override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
        Futures.immediateFuture(
            Resources.Builder()
                .setVersion(RESOURCES_VERSION)
                .build()
        )
}

次に、AndroidManifest.xml ファイルの <application> タグ内にサービスを追加します。

<service
    android:name=".snippets.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>

権限とインテント フィルタにより、このサービスがタイル プロバイダとして登録されます。

アイコン、ラベル、説明、プレビュー リソースは、ユーザーがスマートフォンまたはスマートウォッチでタイルを設定するときに表示されます。

タイルサービスのライフサイクルの概要

アプリ マニフェストで TileService を作成して宣言したら、タイルサービスの状態変化に応答できます。

TileServiceバインドされたサービスです。TileService は、アプリのリクエストの結果として、またはシステムが通信する必要がある場合にバインドされます。一般的なバインド サービスのライフサイクルには、onCreate()onBind()onUnbind()onDestroy() の 4 つのコールバック メソッドが含まれています。サービスが新しいライフサイクル フェーズに入るたびに、これらのメソッドが呼び出されます。

バインドされたサービスのライフサイクルを制御するコールバックに加えて、TileService ライフサイクルに固有の他のメソッドを実装できます。すべてのタイルサービスは、システムからの更新リクエストに応答するために onTileRequest()onTileResourcesRequest() を実装する必要があります。

  • onTileAddEvent(): ユーザーがタイルを初めて追加したとき、およびユーザーがタイルを削除して再度追加した場合にのみ、システムがこのメソッドを呼び出します。1 回限りの初期化を行うには、このタイミングが最適です。

    onTileAddEvent() は、システムによってタイルが作成されるたびに呼び出されるのではなく、タイルのセットが再構成される場合にのみ呼び出されます。たとえば、デバイスが再起動または電源投入された場合、すでに追加されているタイルは onTileAddEvent() で呼び出されません。代わりに getActiveTilesAsync() を使用して、ユーザーに属する有効なタイルのスナップショットを取得できます。

  • onTileRemoveEvent(): ユーザーがタイルを削除した場合にのみ、システムがこのメソッドを呼び出します。

  • onTileEnterEvent(): このプロバイダが提供するタイルが画面に表示されたときに、システムがこのメソッドを呼び出します。

  • onTileLeaveEvent(): このプロバイダが提供するタイルが画面から外れたときに、システムがこのメソッドを呼び出します。

  • onTileRequest(): システムがこのプロバイダから新しいタイムラインをリクエストすると、このメソッドが呼び出されます。

  • onTileResourcesRequest(): システムがこのプロバイダにリソース バンドルをリクエストすると、このメソッドが呼び出されます。これは、タイルが初めて読み込まれるときや、リソース バージョンが変更されるたびに発生する可能性があります。

アクティブなタイルをクエリする

アクティブ タイルは、スマートウォッチに表示するために追加されたタイルです。TileService の静的メソッド getActiveTilesAsync() を使用して、アプリに属するアクティブなタイルをクエリします。

タイルの UI を作成する

タイルのレイアウトは、ビルダー パターンを使用して記述し、レイアウト コンテナと基本的なレイアウト要素からなるツリーのように作成します。各レイアウト要素にはプロパティがあり、さまざまなセッター メソッドで設定できます。

基本的なレイアウト要素

protolayout ライブラリの次の視覚的要素とマテリアル コンポーネントがサポートされています。

  • Text: テキスト文字列をレンダリングし、必要に応じて折り返します。
  • Image: 画像をレンダリングします。
  • Spacer: 要素間にパディングを設定します。背景色を設定するときは区切りとして機能します。

マテリアル コンポーネント

基本要素に加えて、protolayout-material ライブラリにはマテリアル デザイン ユーザー インターフェースの推奨事項に沿ったタイルデザインを実現するためのコンポーネントが用意されています。

  • Button: アイコンを含むようにデザインされた、クリック可能な円形のコンポーネント。
  • Chip: 最大 2 行のテキストと任意のアイコンを含むようにデザインされた、クリック可能なスタジアム形のコンポーネント。

  • CompactChip: 1 行のテキストを含むようにデザインされた、クリック可能なスタジアム形のコンポーネント。

  • TitleChip: Chip に似ているが、タイトル テキストを表示できるように高さが大きくなっている、クリック可能なスタジアム形のコンポーネント。

  • CircularProgressIndicator: EdgeContentLayout 内に配置して画面の端に進行状況を表示できる、円形の進行状況インジケーター。

レイアウト コンテナ

次のコンテナとマテリアル レイアウトがサポートされています。

  • Row: 子要素を水平方向に並べます。
  • Column: 子要素を垂直方向に並べます。
  • Box: 子要素を重ね合わせます。
  • Arc: 子要素を環状に並べます。
  • Spannable: テキストのセクションに特定の FontStyles を適用し、テキストや画像の間に入れます。詳細については、Spannable をご覧ください。

どのコンテナにも、子を 1 つ以上含めることができます。子はコンテナにすることもできます。たとえば、Column に子として複数の Row 要素を含めることができます。この場合、格子状のレイアウトになります。

一例として、コンテナ レイアウトと 2 つの子レイアウト要素を持つタイルは次のようになります。

Kotlin

private fun myLayout(): LayoutElement =
    Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build()

Java

private LayoutElement myLayout() {
    return new Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(new Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(new Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build();
}

マテリアル レイアウト

基本的なレイアウトに加えて、protolayout-material ライブラリには、特定の「スロット」内に要素を保持するための独自のレイアウトがいくつか用意されています。

  • PrimaryLayout: 1 つのプライマリ アクション CompactChip を下部に配置し、その中央にコンテンツを重ねます。

  • MultiSlotLayout: プライマリ ラベルとセカンダリ ラベルを配置し、その間にオプションのコンテンツを配置して、下部にオプションの CompactChip を配置します。

  • MultiButtonLayout: マテリアル ガイドラインに沿って並んだボタンのセットを配置します。

  • EdgeContentLayout: CircularProgressIndicator など、コンテンツを画面の端に配置します。このレイアウトを使用すると、その中のコンテンツには適切な余白とパディングが自動的に適用されます。

円弧

サポートされている 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 種類があります。

  • SpanText: テキストを特定のスタイルでレンダリングします。
  • SpanImage: テキストとともに画像をインラインでレンダリングします。

たとえば、次のコードサンプルに示すように、「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 つがあります。

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()
);
}