スライス テンプレート

このドキュメントでは、スライスを作成するための、Android Jetpack に含まれるテンプレート ビルダーの使い方について詳しく説明します。

スライス テンプレートの定義

スライスは、ListBuilder を使用して作成できます。ListBuilder を使用すると、表示するリストにさまざまな種類の行を追加できます。このセクションでは、各種行タイプとその作成方法について説明します。

SliceAction

スライス テンプレートの最も基本的な要素は、SliceAction です。SliceAction は次のいずれかで、これにはラベルと PendingIntent が含まれます。

  • アイコンボタン
  • デフォルトの切り替えボタン
  • カスタムの切り替えボタン(オンとオフの状態のドローアブル)

SliceAction は、このセクションでこれから説明するテンプレート ビルダーで使用します。SliceAction には次の画像モードがあります。これにより、画像でのアクションの表示方法を指定します。

  • ICON_IMAGE: 非常に小さなサイズで着色可能
  • SMALL_IMAGE: 小さなサイズで着色不可
  • LARGE_IMAGE: 最大サイズで着色不可

HeaderBuilder

通常、テンプレートのヘッダーは HeaderBuilder で指定します。 ヘッダーは以下のものをサポートします。

  • タイトル
  • サブタイトル
  • サマリー サブタイトル
  • メイン アクション

ヘッダー設定の例を以下に示します。なお、グレーのボックスは、アイコンとパディングが表示される予定の場所を示します。

さまざまなサーフェス上でのヘッダーの表示

スライスが必要な場合、表示するサーフェスによってスライスの表示方法が決まります。なお、表示方法はホストするサーフェスによって多少異なります。

小さい形式では通常、ヘッダーのみが表示されます(ヘッダーがある場合)。ヘッダーのサマリーを指定した場合は、サブタイトル テキストの代わりにサマリー テキストが表示されます。

テンプレートにヘッダーを指定していない場合は、通常は ListBuilder に追加した最初の行が代わりに表示されます。

HeaderBuilder の例 - ヘッダー付きの単純なリストのスライス

Kotlin

    fun createSliceWithHeader(sliceUri: Uri) =
        list(context, sliceUri, ListBuilder.INFINITY) {
            setAccentColor(0xff0F9D) // Specify color for tinting icons
            header {
                title = "Get a ride"
                subtitle = "Ride in 4 min"
                summary = "Work in 1 hour 45 min | Home in 12 min"
            }
            row {
                title = "Home"
                subtitle = "12 miles | 12 min | $9.00"
                addEndItem(
                    IconCompat.createWithResource(context, R.drawable.ic_home),
                    ListBuilder.ICON_IMAGE
                )
            }
        }
    

Java

    public Slice createSliceWithHeader(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }

        // Construct the parent.
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                .setAccentColor(0xff0F9D58) // Specify color for tinting icons.
                .setHeader( // Create the header and add to slice.
                        new HeaderBuilder()
                                .setTitle("Get a ride")
                                .setSubtitle("Ride in 4 min.")
                                .setSummary("Work in 1 hour 45 min | Home in 12 min.")
                ).addRow(new RowBuilder() // Add a row.
                        .setPrimaryAction(
                                createActivityAction()) // A slice always needs a SliceAction.
                        .setTitle("Home")
                        .setSubtitle("12 miles | 12 min | $9.00")
                        .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                                SliceHints.ICON_IMAGE)
                ); // Add more rows if needed...
        return listBuilder.build();
    }
    

ヘッダー内の SliceAction

スライス ヘッダーには、SliceAction も表示できます。

Kotlin

    fun createSliceWithActionInHeader(sliceUri: Uri): Slice {
        // Construct our slice actions.
        val noteAction = SliceAction.create(
            takeNoteIntent,
            IconCompat.createWithResource(context, R.drawable.ic_pencil),
            ICON_IMAGE,
            "Take note"
        )

        val voiceNoteAction = SliceAction.create(
            voiceNoteIntent,
            IconCompat.createWithResource(context, R.drawable.ic_mic),
            ICON_IMAGE,
            "Take voice note"
        )

        val cameraNoteAction = SliceAction.create(
            cameraNoteIntent,
            IconCompat.createWithResource(context, R.drawable.ic_camera),
            ICON_IMAGE,
            "Create photo note"
        )

        // Construct the list.
        return list(context, sliceUri, ListBuilder.INFINITY) {
            setAccentColor(0xfff4b4) // Specify color for tinting icons
            header {
                title = "Create new note"
                subtitle = "Easily done with this note taking app"
            }
            addAction(noteAction)
            addAction(voiceNoteAction)
            addAction(cameraNoteAction)
        }
    }
    

Java

    public Slice createSliceWithActionInHeader(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        // Construct our slice actions.
        SliceAction noteAction = SliceAction.create(takeNoteIntent,
                IconCompat.createWithResource(getContext(), R.drawable.ic_pencil),
                ListBuilder.ICON_IMAGE, "Take note");

        SliceAction voiceNoteAction = SliceAction.create(voiceNoteIntent,
                IconCompat.createWithResource(getContext(), R.drawable.ic_mic),
                ListBuilder.ICON_IMAGE,
                "Take voice note");

        SliceAction cameraNoteAction = SliceAction.create(cameraNoteIntent,
                IconCompat.createWithResource(getContext(), R.drawable.ic_camera),
                ListBuilder.ICON_IMAGE,
                "Create photo note");

        // Construct the list.
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                .setAccentColor(0xfff4b400) // Specify color for tinting icons
                .setHeader(new HeaderBuilder() // Construct the header.
                        .setTitle("Create new note")
                        .setSubtitle("Easily done with this note taking app")
                )
                .addRow(new RowBuilder()
                        .setTitle("Enter app")
                        .setPrimaryAction(createActivityAction())
                )
                // Add the actions to the ListBuilder.
                .addAction(noteAction)
                .addAction(voiceNoteAction)
                .addAction(cameraNoteAction);
        return listBuilder.build();
    }
    

RowBuilder

コンテンツの行を作成するには、RowBuilder を使用します。行は以下のいずれをもサポートしています。

  • タイトル
  • サブタイトル
  • 開始アイテム: SliceAction、アイコン、タイムスタンプ
  • 終了アイテム: SliceAction、アイコン、タイムスタンプ
  • メイン アクション

行コンテンツは複数の方法で組み合わせることができますが、次の制限があります。

  • 開始アイテムはスライスの最初の行に表示されない
  • 終了アイテムを SliceAction オブジェクトと Icon オブジェクトの組み合わせにすることはできない
  • 行に含められるタイムスタンプは 1 つのみ

以下の画像は、コンテンツの行の例です。なお、グレーのボックスは、アイコンとパディングが表示される予定の場所を示します。

RowBuilder の例 - Wi-Fi の切り替え

下記の例は、メイン アクションとデフォルトの切り替えボタンを含む行を示しています。

Kotlin

    fun createActionWithActionInRow(sliceUri: Uri): Slice {
        // Primary action - open wifi settings.
        val wifiAction = SliceAction.create(
            wifiSettingsPendingIntent,
            IconCompat.createWithResource(context, R.drawable.ic_wifi),
            ICON_IMAGE,
            "Wi-Fi Settings"
        )

        // Toggle action - toggle wifi.
        val toggleAction = SliceAction.createToggle(
            wifiTogglePendingIntent,
            "Toggle Wi-Fi",
            isConnected /* isChecked */
        )

        // Create the parent builder.
        return list(context, wifiUri, ListBuilder.INFINITY) {
            setAccentColor(0xff4285) // Specify color for tinting icons / controls.
            row {
                title = "Wi-Fi"
                primaryAction = wifiAction
                addEndItem(toggleAction)
            }
        }
    }
    

Java

    public Slice createActionWithActionInRow(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        // Primary action - open wifi settings.
        SliceAction primaryAction = SliceAction.create(wifiSettingsPendingIntent,
                IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
                ListBuilder.ICON_IMAGE,
                "Wi-Fi Settings"
        );

        // Toggle action - toggle wifi.
        SliceAction toggleAction = SliceAction.createToggle(wifiTogglePendingIntent,
                "Toggle Wi-Fi", isConnected /* isChecked */);

        // Create the parent builder.
        ListBuilder listBuilder = new ListBuilder(getContext(), wifiUri, ListBuilder.INFINITY)
                // Specify color for tinting icons / controls.
                .setAccentColor(0xff4285f4)
                // Create and add a row.
                .addRow(new RowBuilder()
                        .setTitle("Wi-Fi")
                        .setPrimaryAction(primaryAction)
                        .addEndItem(toggleAction));
        // Build the slice.
        return listBuilder.build();
    }
    

GridBuilder

コンテンツのグリッドを作成するには、GridBuilder を使用します。グリッドは、次の画像タイプをサポートします。

  • ICON_IMAGE: 非常に小さなサイズで着色可能
  • SMALL_IMAGE: 小さなサイズで着色不可
  • LARGE_IMAGE: 最大サイズで着色不可

グリッドセルを作成するには、CellBuilder を使用します。セルは最大 2 行のテキストと 1 つの画像をサポートします。セルを空にすることはできません。

次の画像はグリッドの例です。

GridRowBuilder の例 - 付近のレストラン

下記の例は、画像とテキストを含むグリッドの行を示しています。

Kotlin

    fun createSliceWithGridRow(sliceUri: Uri): Slice {
        // Create the parent builder.
        return list(context, sliceUri, ListBuilder.INFINITY) {
            header {
                title = "Famous restaurants"
                primaryAction = SliceAction.create(
                    pendingIntent, icon, ListBuilder.ICON_IMAGE, "Famous restaurants"
                )
            }
            gridRow {
                cell {
                    addImage(image1, LARGE_IMAGE)
                    addTitleText("Top Restaurant")
                    addText("0.3 mil")
                    contentIntent = intent1
                }
                cell {
                    addImage(image2, LARGE_IMAGE)
                    addTitleText("Fast and Casual")
                    addText("0.5 mil")
                    contentIntent = intent2
                }
                cell {
                    addImage(image3, LARGE_IMAGE)
                    addTitleText("Casual Diner")
                    addText("0.9 mi")
                    contentIntent = intent3
                }
                cell {
                    addImage(image4, LARGE_IMAGE)
                    addTitleText("Ramen Spot")
                    addText("1.2 mi")
                    contentIntent = intent4
                }
            }
        }
    }
    

Java

    public Slice createSliceWithGridRow(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        // Create the parent builder.
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                .setHeader(
                        // Create the header.
                        new HeaderBuilder()
                                .setTitle("Famous restaurants")
                                .setPrimaryAction(SliceAction
                                        .create(pendingIntent, icon, ListBuilder.ICON_IMAGE,
                                                "Famous restaurants"))
                )
                // Add a grid row to the list.
                .addGridRow(new GridRowBuilder()
                        // Add cells to the grid row.
                        .addCell(new CellBuilder()
                                .addImage(image1, ListBuilder.LARGE_IMAGE)
                                .addTitleText("Top Restaurant")
                                .addText("0.3 mil")
                                .setContentIntent(intent1)
                        ).addCell(new CellBuilder()
                                .addImage(image2, ListBuilder.LARGE_IMAGE)
                                .addTitleText("Fast and Casual")
                                .addText("0.5 mil")
                                .setContentIntent(intent2)
                        )
                        .addCell(new CellBuilder()
                                .addImage(image3, ListBuilder.LARGE_IMAGE)
                                .addTitleText("Casual Diner")
                                .addText("0.9 mi")
                                .setContentIntent(intent3))
                        .addCell(new CellBuilder()
                                .addImage(image4, ListBuilder.LARGE_IMAGE)
                                .addTitleText("Ramen Spot")
                                .addText("1.2 mi")
                                .setContentIntent(intent4))
                        // Every slice needs a primary action.
                        .setPrimaryAction(createActivityAction())
                );
        return listBuilder.build();
    }
    

RangeBuilder

進行状況バーまたは入力範囲(スライダーなど)のどちらかを含む行を作成するには、RangeBuilder を使用します。

次の画像は、進行状況バーとスライダーの例です。

RangeBuilder の例 - スライダー

下記の例は、InputRangeBuilder を使用して音量スライダーを含むスライスを作成する方法を示しています。進捗状況の行を作成するには、addRange() を使用します。

Kotlin

    fun createSliceWithRange(sliceUri: Uri): Slice {
        return list(context, sliceUri, ListBuilder.INFINITY) {
            inputRange {
                title = "Ring Volume"
                inputAction = volumeChangedPendingIntent
                max = 100
                value = 30
            }
        }
    }
    

Java

    public Slice createSliceWithRange(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        // Construct the parent.
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                .addRow(new RowBuilder() // Every slice needs a row.
                        .setTitle("Enter app")
                         // Every slice needs a primary action.
                        .setPrimaryAction(createActivityAction())
                )
                .addInputRange(new InputRangeBuilder() // Create the input row.
                        .setTitle("Ring Volume")
                        .setInputAction(volumeChangedPendingIntent)
                        .setMax(100)
                        .setValue(30)
                );
        return listBuilder.build();
    }
    

遅延コンテンツ

スライスは、できるだけ早く SliceProvider#onBindSlice から返す必要があります。 呼び出しに時間がかかると、ちらつきや急激なサイズ変更など、表示上の問題が発生する可能性があります。

スライス コンテンツがすぐに読み込めない場合は、ビルダー内で読み込み中のコンテンツを注視しながら、null またはプレースホルダ コンテンツを使用してスライスを作成します。コンテンツを表示する準備ができたら、スライスの URI を使って getContentResolver().notifyChange(sliceUri, null) を呼び出します。これにより SliceProvider#onBindSlice が呼び出され、新しいコンテンツでスライスが再作成されます。

遅延コンテンツの例 - Ride to work

下記の [Ride to work] の行は、職場までの距離が都度変わるため、すぐに表示できない可能性があります。次のコード例は、コンテンツの読み込み中に null サブタイトルをプレースホルダとして使用する方法を示しています。

Kotlin

    fun createSliceShowingLoading(sliceUri: Uri): Slice {
        // We’re waiting to load the time to work so indicate that on the slice by
        // setting the subtitle with the overloaded method and indicate true.
        return list(context, sliceUri, ListBuilder.INFINITY) {
            row {
                title = "Ride to work"
                setSubtitle(null, true)
                addEndItem(IconCompat.createWithResource(context, R.drawable.ic_work), ICON_IMAGE)
            }
        }
    }
    

Java

    public Slice createSliceShowingLoading(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        // Construct the parent.
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                // Construct the row.
                .addRow(new RowBuilder()
                        .setPrimaryAction(createActivityAction())
                        .setTitle("Ride to work")
                        // We’re waiting to load the time to work so indicate that on the slice by
                        // setting the subtitle with the overloaded method and indicate true.
                        .setSubtitle(null, true)
                        .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_work),
                                ListBuilder.ICON_IMAGE)
                );
        return listBuilder.build();
    }

    private SliceAction createActivityAction() {
        return SliceAction.create(
                PendingIntent.getActivity(
                        getContext(),
                        0,
                        new Intent(getContext(), MainActivity.class),
                        0
                ),
                IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                ListBuilder.ICON_IMAGE,
                "Enter app"
        );
    }
    

スライス内でのスクロールが無効の場合の処理

スライス テンプレートを表示するサーフェスが、テンプレート内でのスクロールをサポートしていない場合があります。この場合、コンテンツの一部が表示されないことも考えられます。

例として、Wi-Fi ネットワークのリストを表示するスライスを考えます。

Wi-Fi リストが長いにもかかわらずスクロールが無効の場合は、[See more] ボタンを追加することで、リスト内のすべてのアイテムが表示されるようにできます。このボタンを追加するには、次の例のように addSeeMoreAction() を使用します。

Kotlin

    fun seeMoreActionSlice(sliceUri: Uri) =
        list(context, sliceUri, ListBuilder.INFINITY) {
            // ...
            setSeeMoreAction(seeAllNetworksPendingIntent)
            // ...
        }
    

Java

    public Slice seeMoreActionSlice(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY);
        // ...
        listBuilder.setSeeMoreAction(seeAllNetworksPendingIntent);
        // ...
        return listBuilder.build();
    }
    

これにより、次の画像のような表示になります。

[See more] をタップすると、seeAllNetworksPendingIntent が送信されます。

別の方法として、RowBuilder を追加することでカスタム メッセージや行を表示することもできます。

Kotlin

    fun seeMoreRowSlice(sliceUri: Uri) =
        list(context, sliceUri, ListBuilder.INFINITY) {
            // ...
            seeMoreRow {
                title = "See all available networks"
                addEndItem(
                    IconCompat.createWithResource(context, R.drawable.ic_right_caret), ICON_IMAGE
                )
                primaryAction = SliceAction.create(
                    seeAllNetworksPendingIntent,
                    IconCompat.createWithResource(context, R.drawable.ic_wifi),
                    ListBuilder.ICON_IMAGE,
                    "Wi-Fi Networks"
                )
            }
        }
    

Java

    public Slice seeMoreRowSlice(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
                // ...
                .setSeeMoreRow(new RowBuilder()
                        .setTitle("See all available networks")
                        .addEndItem(IconCompat
                                        .createWithResource(getContext(), R.drawable
                                                .ic_right_caret),
                                ListBuilder.ICON_IMAGE)
                        .setPrimaryAction(SliceAction.create(seeAllNetworksPendingIntent,
                                IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
                                ListBuilder.ICON_IMAGE,
                                "Wi-Fi Networks"))
                );
        // ...
        return listBuilder.build();
    }
    

この方法で追加した行またはアクションは、次のいずれかの条件が満たされた場合にのみ表示されます。

  • スライスのプレゼンターにより、ビューのスクロールが無効化されている
  • 利用できるスペースにすべての行を表示できない

テンプレートの組み合わせ

複数の種類の行を組み合わせることで、リッチで動的なスライスを作成できます。たとえば、1 つのスライスに、ヘッダー行、1 つの画像を含むグリッド、テキストセルが 2 つあるグリッド、を含めることができます。

また、次の例では、1 つのスライスにヘッダー行と 3 つのセルのグリッドが含まれています。