Android-Benutzeroberfläche für Absender anpassen

Du kannst Cast-Widgets anpassen, indem du die Farben festlegst, die Schaltflächen, den Text und die Miniaturansichten gestaltest und die Arten von Schaltflächen auswählst, die angezeigt werden sollen.

App-Design anpassen

In diesem Beispiel wird ein benutzerdefinierter Designstil Theme.CastVideosTheme erstellt, mit dem benutzerdefinierte Farben, ein Stil für das Einführungs-Overlay, ein Stil für den Mini-Controller und ein Stil für den erweiterten Controller definiert werden können.

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Set AppCompat's color theming attrs -->
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:textColorPrimary">@color/primary_text</item>
    <item name="android:textColorSecondary">@color/secondary_text</item>
    <item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
    <item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
    <item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
</style>

Mit den letzten drei Zeilen oben können Sie im Rahmen dieses Designs Stile für das Einführungs-Overlay, den Mini-Controller und den erweiterten Controller definieren. Beispiele finden Sie in den folgenden Abschnitten.

Cast-Symbol anpassen

So fügen Sie dem Design Ihrer App ein benutzerdefiniertes mediaRouteTheme hinzu:

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <!-- ... -->
  <item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
</style>

Deklarieren Sie Ihr benutzerdefiniertes Media Router-Design und ein benutzerdefiniertes mediaRouteButtonStyle:

<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
  <item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>

<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
  <item name="mediaRouteButtonTint">#EEFF41</item>
</style>

setTint sollte verwendet werden, wenn die Version der Support-Bibliothek neuer als 26.0.0 ist. Verwenden Sie für ältere Versionen der Supportbibliothek stattdessen buttonTint.

Design des Einführungs-Overlays anpassen

Die Klasse IntroductoryOverlay unterstützt verschiedene Stilattribute, die Ihre App in einem benutzerdefinierten Design überschreiben kann. In diesem Beispiel wird gezeigt, wie Sie die Textdarstellung sowohl der Schaltfläche als auch des Titels über dem Overlay-Widget überschreiben:

<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
    <item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
    <item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title"parent="android:style/TextAppearance.Large">
    <item name="android:textColor">#FFFFFF</item>
</style>

Mini-Controller anpassen

Design anpassen

Die Klasse MiniControllerFragment unterstützt verschiedene Stilattribute, die Ihre App in einem benutzerdefinierten Design überschreiben kann. In diesem Beispiel wird gezeigt, wie Sie die Anzeige des Thumbnail-Bilds aktivieren, die Textdarstellung der Unterüberschrift und der Untertitel überschreiben, die Farben festlegen und die Schaltflächen anpassen:

<style name="CustomCastMiniController" parent="CastMiniController">
    <item name="castShowImageThumbnail">true</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
    <item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
    <item name="castBackground">#FFFFFF</item>
    <item name="castProgressBarColor">#FFFFFF</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_mini_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_mini_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_mini_controller_stop</item>
    <item name="castLargePlayButtonDrawable">@drawable/cast_ic_mini_controller_play_large</item>
    <item name="castLargePauseButtonDrawable">@drawable/cast_ic_mini_controller_pause_large</item>
    <item name="castLargeStopButtonDrawable">@drawable/cast_ic_mini_controller_stop_large</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_mini_controller_skip_prev</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_mini_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_mini_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_mini_controller_forward30</item>
    <item name="castMuteToggleButtonDrawable">@drawable/cast_ic_mini_controller_mute</item>
    <item name="castClosedCaptionsButtonDrawable">@drawable/cast_ic_mini_controller_closed_caption</item
</style>

Auswahl-Buttons

Ein MiniControllerFragment hat drei Slots, in denen das Albumcover angezeigt werden kann, und zwei Schaltflächen oder drei Steuerschaltflächen, wenn das Albumcover nicht ausgefüllt ist.

SLOT  SLOT  SLOT
  1     2     3

Standardmäßig wird im Fragment ein Ein/Aus-Button für die Wiedergabe/Pause angezeigt. Entwickler können das Attribut castControlButtons verwenden, um zu überschreiben, welche Schaltflächen angezeigt werden. Die unterstützten Steuerungsschaltflächen sind als ID-Ressourcen definiert:

Schaltflächenart Beschreibung
@id/cast_button_type_empty In diesem Slot darf keine Schaltfläche platziert werden
@id/cast_button_type_custom Benutzerdefinierter Button
@id/cast_button_type_play_pause_toggle Wechselt zwischen Wiedergabe und Pause
@id/cast_button_type_skip_previous Springt zum vorherigen Element in der Warteschlange
@id/cast_button_type_skip_next Springt zum nächsten Element in der Warteschlange
@id/cast_button_type_rewind_30_seconds Spult die Wiedergabe um 30 Sekunden zurück
@id/cast_button_type_forward_30_seconds Spult die Wiedergabe um 30 Sekunden vor
@id/cast_button_type_mute_toggle Schaltet den Empfänger stumm und hebt die Stummschaltung auf
@id/cast_button_type_closed_caption Öffnet ein Dialogfeld, in dem Sie Text- und Audiotracks auswählen können

Hier ist ein Beispiel, bei dem das Albumcover, ein Ein/Aus-Button für Wiedergabe/Pause und ein Button zum Vorspringen in dieser Reihenfolge von links nach rechts verwendet werden:

<array name="cast_mini_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_play_pause_toggle</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
</array>
...
<fragment
    android:id="@+id/cast_mini_controller"
    ...
    app:castControlButtons="@array/cast_mini_controller_control_buttons"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment">

Warnung: Dieses Array muss genau drei Elemente enthalten, da sonst eine Laufzeitausnahme ausgelöst wird. Wenn Sie an einer Stelle keine Schaltfläche anzeigen möchten, verwenden Sie @id/cast_button_type_empty.

Benutzerdefinierte Tasten hinzufügen

Ein MiniControllerFragment unterstützt das Hinzufügen benutzerdefinierter Steuerelemente, die nicht vom SDK bereitgestellt werden, z. B. eine „Daumen hoch“-Schaltfläche. Folgende Schritte sind auszuführen:

  1. Geben Sie einen Slot für eine benutzerdefinierte Schaltfläche mit @id/cast_button_type_custom im Attribut castControlButtons des MiniControllerFragment an.

  2. Implementieren Sie eine abgeleitete Klasse von UIController. UIController enthält Methoden, die vom SDK aufgerufen werden, wenn sich der Status der Übertragungssitzung oder der Mediensitzung ändert. Ihre abgeleitete Klasse von UIController sollte einen ImageView als einen der Parameter verwenden und den Status nach Bedarf aktualisieren.

  3. Erstellen Sie eine Unterklasse von MiniControllerFragment, überschreiben Sie onCreateView und rufen Sie getButtonImageViewAt(int) auf, um die ImageView für diese benutzerdefinierte Schaltfläche abzurufen. Rufen Sie dann bindViewToUIController(View, UIController) auf, um die Ansicht mit Ihrer benutzerdefinierten UIController zu verknüpfen.

  4. Informationen zum Umgang mit der Aktion über die benutzerdefinierte Schaltfläche findest du unter MediaIntentReceiver im Abschnitt Benutzerdefinierte Aktionen hinzufügen.

    Hier ist ein Beispiel für die Verknüpfung einer Taste an Slot 2 mit einem UIController namens MyCustomUIController:

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
Kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyMiniControllerFragment.kt
class MyMiniControllerFragment : MiniControllerFragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
Java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
            mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyMiniControllerFragment.java
class MyMiniControllerFragment extends MiniControllerFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}

Erweiterten Controller anpassen

Design anpassen

Wenn die Aktivität eines erweiterten Controllers eine Symbolleiste mit dunklem Design verwendet, kannst du für die Symbolleiste ein Design mit hellem Text und einer hellen Symbolfarbe festlegen:

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="castExpandedControllerToolbarStyle">
        @style/ThemeOverlay.AppCompat.Dark.ActionBar
    </item>
</style>

Du kannst eigene Bilder angeben, die zum Zeichnen der Schaltflächen auf dem erweiterten Controller verwendet werden:

<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castButtonColor">@null</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_expanded_controller_skip_previous</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_expanded_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_expanded_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_expanded_controller_forward30</item>
</style>

Auswahl-Buttons

Die Aktivität des maximierten Controllers hat fünf Slots für Steuerungsschaltflächen. Im mittleren Slot wird immer ein Schalter zum Abspielen/Pausieren angezeigt. Er kann nicht konfiguriert werden. Die anderen vier Slots können von der Sender-App von links nach rechts konfiguriert werden.

SLOT  SLOT  PLAY/PAUSE  SLOT  SLOT
  1     2     BUTTON      3     4

Standardmäßig werden in der Aktivität von links nach rechts eine Schaltfläche für Untertitel, eine Schaltfläche zum Überspringen zum vorherigen Element, eine Schaltfläche zum Überspringen zum nächsten Element und eine Schaltfläche zum Stummschalten angezeigt. Entwickler können das Attribut castControlButtons verwenden, um zu überschreiben, welche Schaltflächen in welchen Slots angezeigt werden. Die Liste der unterstützten Steuerungsschaltflächen wird als ID-Ressourcen definiert, die mit den Schaltflächentypen für Mini-Controller-Schaltflächen identisch sind.

Hier ist ein Beispiel, bei dem ein Button zum Zurückspulen im zweiten Slot und ein Button zum Vorspringen im dritten Slot platziert wird. Der erste und der letzte Slot bleiben leer:

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
    <item>@id/cast_button_type_empty</item>
</array>
...
// styles.xml
<style name="Theme.MyTheme">
    <item name="castExpandedControllerStyle">
        @style/CustomCastExpandedController
    </item>
</style>
...
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castControlButtons">
        @array/cast_expanded_controller_control_buttons
    </item>
</style>

Das Array muss genau vier Elemente enthalten, andernfalls wird eine Laufzeitausnahme ausgelöst. Wenn Sie an einer Stelle keine Schaltfläche anzeigen möchten, verwenden Sie @id/cast_button_type_empty. CastContext kann den Lebenszyklus und die Darstellung dieser Aktivität verwalten.

Benutzerdefinierte Tasten hinzufügen

Ein ExpandedControllerActivity unterstützt das Hinzufügen benutzerdefinierter Steuerelemente, die nicht vom SDK bereitgestellt werden, z. B. eine „Daumen hoch“-Schaltfläche. Folgende Schritte sind auszuführen:

  1. Geben Sie einen Slot für eine benutzerdefinierte Schaltfläche mit @id/cast_button_type_custom im Attribut castControlButtons des ExpandedControllerActivity an. Anschließend kannst du mit getButtonImageViewAt(int) die ImageView für diese benutzerdefinierte Taste abrufen.

  2. Implementieren Sie eine abgeleitete Klasse von UIController. UIController enthält Methoden, die vom SDK aufgerufen werden, wenn sich der Status der Übertragungssitzung oder der Mediensitzung ändert. Ihre Unterklasse von UIController sollte einen ImageView als einen der Parameter verwenden und den Status nach Bedarf aktualisieren.

  3. Erstelle eine Unterklasse von ExpandedControllerActivity, überschreibe dann onCreate und rufe getButtonImageViewAt(int) auf, um das Ansichtsobjekt der Schaltfläche abzurufen. Rufen Sie dann bindViewToUIController(View, UIController) auf, um die Ansicht mit Ihrer benutzerdefinierten UIController zu verknüpfen.

  4. Unter MediaIntentReceiver im Abschnitt Benutzerdefinierte Aktionen hinzufügen erfährst du, wie du die Aktion deiner benutzerdefinierten Schaltfläche verarbeitest.

Hier ist ein Beispiel für die Verknüpfung einer Schaltfläche in Slot 2 mit einem UIController namens MyCustomUIController:

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
Kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyExpandedControllerActivity.kt
internal class MyExpandedControllerActivity : ExpandedControllerActivity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
Java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
        mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyExpandedControllerActivity.java
class MyExpandedControllerActivity extends ExpandedControllerActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}