Vorlagen für App-Teile

Dieses Dokument enthält Details zur Verwendung der Vorlagen-Builder in Android Jetpack zum Erstellen von Slices.

Slice-Vorlage definieren

Slices werden mit einem ListBuilder erstellt. Mit ListBuilder können Sie verschiedene Zeilentypen hinzufügen, die in einer Liste angezeigt werden. In diesem Abschnitt werden die einzelnen Zeilentypen und ihr Aufbau beschrieben.

SliceAction (Slice-Aktion)

Das einfachste Element einer Slice-Vorlage ist ein SliceAction. Ein SliceAction enthält ein Label und einen PendingIntent und ist eines der folgenden:

  • Symbolschaltfläche
  • Standard-Ein/Aus-Schaltfläche
  • Benutzerdefinierte Ein/Aus-Schaltfläche (ein Drawable mit Ein/Aus-Zustand)

SliceAction wird von den im Rest dieses Abschnitts beschriebenen Vorlagen-Builder verwendet. Für SliceAction kann ein Bildmodus definiert werden, der bestimmt, wie das Bild für die Aktion präsentiert wird:

  • ICON_IMAGE: winzig und abtönbar
  • SMALL_IMAGE: klein, nicht abtönbar
  • LARGE_IMAGE: größte Größe und nicht abtönbar

HeaderBuilder

In den meisten Fällen sollten Sie mit HeaderBuilder einen Header für Ihre Vorlage festlegen. Ein Header kann Folgendes unterstützen:

  • Titel
  • Untertitel
  • Untertitel der Zusammenfassung
  • Primäre Aktion

Im Folgenden finden Sie einige Beispiele für Header-Konfigurationen. In den grauen Feldern werden mögliche Symbole und Positionen angezeigt, die mit einem Innenrand versehen sind:

Rendering von Headern auf verschiedenen Oberflächen

Wenn ein Slice erforderlich ist, bestimmt die Anzeigeoberfläche, wie das Slice gerendert wird. Das Rendering kann je nach Hosting-Oberfläche etwas variieren.

In kleineren Formaten wird normalerweise nur der Header angezeigt, falls vorhanden. Wenn Sie eine Zusammenfassung für die Kopfzeile angegeben haben, wird anstelle des Untertiteltexts der Zusammenfassungstext angezeigt.

Wenn Sie in der Vorlage keine Kopfzeile angegeben haben, wird normalerweise die erste Zeile angezeigt, die dem ListBuilder hinzugefügt wird.

HeaderBuilder-Beispiel – Einfaches Listen-Slice mit Header

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

SliceActions in Headern

Slice-Header können auch SliceActions anzeigen:

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

Sie können eine Inhaltszeile mithilfe eines RowBuilder erstellen. Eine Zeile kann Folgendes unterstützen:

  • Titel
  • Untertitel
  • Startelement: SliceAction, Symbol oder Zeitstempel
  • Endelemente: SliceAction, Symbol oder Zeitstempel
  • Primäre Aktion

Zeileninhalte lassen sich auf verschiedene Arten kombinieren. Dabei gelten die folgenden Einschränkungen:

  • Startelemente werden nicht in der ersten Zeile eines Slice angezeigt.
  • Endelemente dürfen nicht gleichzeitig SliceAction- und Icon-Objekte sein
  • Eine Zeile darf nur einen Zeitstempel enthalten

In den folgenden Bildern sehen Sie Beispielzeilen für Inhalte. Die grauen Felder zeigen mögliche Symbole und die entsprechenden Positionen an:

RowBuilder-Beispiel – WLAN-Ein/Aus-Schaltfläche

Das folgende Beispiel zeigt eine Zeile mit einer primären Aktion und einer Standard-Ein/Aus-Schaltfläche.

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

Mit GridBuilder können Sie ein Inhaltsraster erstellen. Ein Raster kann die folgenden Bildtypen unterstützen:

  • ICON_IMAGE: winzig und abtönbar
  • SMALL_IMAGE: klein, nicht abtönbar
  • LARGE_IMAGE: größte Größe und nicht abtönbar

Eine Zelle im Raster wird mit einem CellBuilder konstruiert. Eine Zelle kann bis zu zwei Textzeilen und ein Bild unterstützen. Eine Zelle darf nicht leer sein.

In den folgenden Bildern sehen Sie Beispiele für Raster:

GridRowBuilder-Beispiel – Restaurants in der Nähe

Das folgende Beispiel zeigt eine Rasterzeile, die Bilder und Text enthält.

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

Mit einem RangeBuilder können Sie eine Zeile erstellen, die entweder eine Fortschrittsanzeige oder einen Eingabebereich wie einen Schieberegler enthält.

Beispiele für den Fortschritt und Schieberegler sind in den folgenden Bildern zu sehen:

RangeBuilder-Beispiel – Slider

Das folgende Beispiel zeigt, wie Sie mithilfe eines InputRangeBuilder ein Slice erstellen, das einen Volume-Schieberegler enthält. Verwenden Sie addRange(), um eine Fortschrittszeile zu erstellen.

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

Verzögerte Inhalte

Sie sollten ein Slice so schnell wie möglich von SliceProvider.onBindSlice() zurückgeben. Zeitintensive Aufrufe können zu Darstellungsproblemen wie Flackern oder einer abrupten Größenanpassung führen.

Wenn Sie Slice-Inhalte haben, die nicht schnell geladen werden können, können Sie den Slice mit Platzhalterinhalten erstellen und im Builder darauf hinweisen, dass der Inhalt geladen wird. Sobald der Inhalt zur Anzeige bereit ist, rufen Sie getContentResolver().notifyChange(sliceUri, null) mit Ihrem Slice-URI auf. Dies führt zu einem weiteren Aufruf von SliceProvider.onBindSlice(), bei dem Sie das Slice noch einmal mit neuem Inhalt erstellen können.

Beispiel für verzögerten Inhalt – Zur Arbeit fahren

In der Zeile „Zur Arbeit fahren“ unten wird die Entfernung zur Arbeit dynamisch bestimmt und ist möglicherweise nicht sofort verfügbar. Der Beispielcode zeigt, wie beim Laden des Inhalts ein Nulluntertitel als Platzhalter verwendet wird:

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

Deaktiviertes Scrollen im Slice behandeln

Die Oberfläche, auf der Ihre Slice-Vorlage zu sehen ist, unterstützt möglicherweise kein Scrollen innerhalb der Vorlage. In diesem Fall werden einige Ihrer Inhalte möglicherweise nicht angezeigt.

Betrachten Sie als Beispiel einen Slice, der eine Liste von WLAN-Netzwerken zeigt:

Wenn die WLAN-Liste lang ist und das Scrollen deaktiviert ist, können Sie die Schaltfläche Mehr anzeigen hinzufügen, damit Nutzer alle Elemente in der Liste sehen können. Sie können diese Schaltfläche mit addSeeMoreAction() hinzufügen, wie im folgenden Beispiel gezeigt:

Kotlin

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

Java

public Slice seeMoreActionSlice(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY);
    // [START_EXCLUDE]
    listBuilder.addRow(new RowBuilder()
            .setTitle("Hello")
            .setPrimaryAction(createActivityAction())
    );
    // [END_EXCLUDE]
    listBuilder.setSeeMoreAction(seeAllNetworksPendingIntent);
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

Dies wird wie in der folgenden Abbildung dargestellt angezeigt:

Wenn Sie auf Mehr anzeigen tippen, wird seeAllNetworksPendingIntent gesendet.

Wenn Sie eine benutzerdefinierte Nachricht oder Zeile bereitstellen möchten, können Sie alternativ einen RowBuilder hinzufügen:

Kotlin

fun seeMoreRowSlice(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        // [START_EXCLUDE]
        // [END_EXCLUDE]
        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)
            // [START_EXCLUDE]
            .addRow(new RowBuilder()
                    .setTitle("Hello")
                    .setPrimaryAction(createActivityAction())
            )
            // [END_EXCLUDE]
            .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"))
            );
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

Die über diese Methode hinzugefügte Zeile oder Aktion wird nur angezeigt, wenn eine der folgenden Bedingungen erfüllt ist:

  • Der Vortragende Ihres Slice hat das Scrollen in der Ansicht deaktiviert
  • Im verfügbaren Platz können nicht alle Zeilen angezeigt werden

Vorlagen kombinieren

Sie können einen umfangreichen, dynamischen Slice erstellen, indem Sie mehrere Zeilentypen kombinieren. Ein Slice kann beispielsweise eine Kopfzeile, ein Raster mit einem einzelnen Bild und ein Raster mit zwei Textzellen enthalten.

Hier sehen Sie ein Slice mit einer Kopfzeile und einem Raster, das drei Zellen enthält.