Personnaliser l'interface utilisateur Android Sender

Vous pouvez personnaliser les widgets Cast en définissant les couleurs, le style des boutons, le texte et l'apparence des miniatures, et en sélectionnant les types de boutons à afficher.

Personnaliser le thème de l'application

Cet exemple crée un style de thème personnalisé Theme.CastVideosTheme qui peut définir des couleurs personnalisées, un style de superposition d'introduction, un style de manette miniature et un style de manette agrandie.

<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>

Les trois dernières lignes ci-dessus vous permettent de définir des styles spécifiques à la superposition d'introduction, à la mini-télécommande et à la manette étendue, dans le cadre de ce thème. Vous trouverez des exemples dans les sections suivantes.

Personnaliser l'icône Cast

Pour ajouter un mediaRouteTheme personnalisé au thème de votre application:

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

Déclarez votre thème de routeur multimédia personnalisé et déclarez un mediaRouteButtonStyle personnalisé:

<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>

Utilisez setTint si la version de la bibliothèque Support est ultérieure à la version 26.0.0. Pour les anciennes versions de la bibliothèque Support, utilisez plutôt buttonTint.

Personnaliser le thème de superposition découverte

La classe IntroductoryOverlay accepte différents attributs de style que votre application peut remplacer dans un thème personnalisé. Cet exemple montre comment remplacer l'apparence du texte du bouton et du titre sur le widget en superposition:

<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>

Personnaliser la mini-télécommande

Personnaliser le thème

La classe MiniControllerFragment accepte différents attributs de style que votre application peut remplacer dans un thème personnalisé. Cet exemple montre comment activer l'affichage de la vignette, remplacer l'apparence du texte du sous-titre et du sous-titre, définir les couleurs et personnaliser les boutons:

<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>

Sélectionner des boutons

Un élément MiniControllerFragment comporte trois emplacements pour afficher la pochette de l'album et deux boutons, ou trois boutons de commande si l'image de l'album n'est pas renseignée.

SLOT  SLOT  SLOT
  1     2     3

Par défaut, le fragment affiche un bouton d'activation de lecture/pause. Les développeurs peuvent utiliser l'attribut castControlButtons pour remplacer les boutons à afficher. Les boutons de commande compatibles sont définis comme des ressources d'ID:

Type de bouton Description
@id/cast_button_type_empty Ne pas placer de bouton dans cet emplacement
@id/cast_button_type_custom Bouton personnalisé
@id/cast_button_type_play_pause_toggle Basculer entre la lecture et la mise en pause
@id/cast_button_type_skip_previous Passer à l'élément précédent dans la file d'attente
@id/cast_button_type_skip_next Passer à l'élément suivant dans la file d'attente
@id/cast_button_type_rewind_30_seconds Revenir en arrière de 30 secondes.
@id/cast_button_type_forward_30_seconds Avancer de 30 secondes dans la lecture
@id/cast_button_type_mute_toggle couper ou réactiver le son du récepteur ;
@id/cast_button_type_closed_caption Ouvre une boîte de dialogue permettant de sélectionner des pistes textuelles et audio

Voici un exemple qui utiliserait la pochette de l'album, un bouton d'activation/de désactivation de lecture/pause et un bouton permettant d'avancer le texte dans l'ordre suivant:

<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">

Avertissement: Ce tableau doit contenir exactement trois éléments, sinon une exception d'exécution sera générée. Si vous ne souhaitez pas afficher de bouton dans un emplacement, utilisez @id/cast_button_type_empty.

Ajouter des boutons personnalisés

Un MiniControllerFragment permet d'ajouter des boutons de commande personnalisés qui ne sont pas fournis par le SDK, tels qu'un bouton "J'aime". Voici la procédure à suivre :

  1. Spécifiez un emplacement contenant un bouton personnalisé à l'aide de @id/cast_button_type_custom dans l'attribut castControlButtons de MiniControllerFragment.

  2. Implémentez une sous-classe de UIController. UIController contient des méthodes appelées par le SDK lorsque l'état de la session Cast ou de la session multimédia change. Votre sous-classe de UIController doit utiliser ImageView comme paramètre et mettre à jour son état si nécessaire.

  3. Sous-classe MiniControllerFragment, puis remplacez onCreateView et appelez getButtonImageViewAt(int) pour obtenir le ImageView correspondant à ce bouton personnalisé. Appelez ensuite bindViewToUIController(View, UIController) pour associer la vue à votre UIController personnalisée.

  4. Pour en savoir plus sur la gestion de l'action à partir de votre bouton personnalisé, consultez la section MediaIntentReceiver sur la page Ajouter des actions personnalisées.

    Voici un exemple d'association d'un bouton à l'emplacement 2 à un UIController appelé 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);
        ...
    }
}

Personnaliser la manette étendue

Personnaliser le thème

Si l'activité d'une manette agrandie utilise une barre d'outils de thème sombre, vous pouvez définir un thème dans la barre d'outils afin d'utiliser du texte clair et une icône claire:

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

Vous pouvez spécifier vos propres images qui serviront à dessiner les boutons de la télécommande agrandie:

<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>

Sélectionner des boutons

L'activité de la manette agrandie comporte cinq emplacements pour afficher les boutons de commande. L'emplacement central affiche toujours un bouton d'activation/de désactivation de lecture/pause et n'est pas configurable. Les quatre autres emplacements peuvent être configurés, de gauche à droite, par l'application expéditeur.

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

Par défaut, l'activité affiche un bouton de sous-titres, un bouton pour accéder au précédent élément, un autre pour passer au suivant, et un bouton pour couper le son de ces quatre emplacements, de gauche à droite. Les développeurs peuvent utiliser l'attribut castControlButtons pour remplacer les boutons à afficher en fonction des emplacements. La liste des boutons de commande compatibles est définie comme des ressources d'ID identiques aux types de boutons pour les mini-boutons de manette.

Voici un exemple qui place un bouton "Retour" dans le deuxième emplacement, un bouton "Avancer" dans le troisième emplacement et en laissant les premier et dernier emplacements vides:

// 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>

Le tableau doit contenir exactement quatre éléments, sinon une exception d'exécution sera générée. Si vous ne souhaitez pas afficher de bouton dans un emplacement, utilisez @id/cast_button_type_empty. CastContext peut gérer le cycle de vie et la présentation de cette activité.

Ajouter des boutons personnalisés

Un ExpandedControllerActivity permet d'ajouter des boutons de commande personnalisés qui ne sont pas fournis par le SDK, tels qu'un bouton "J'aime". Voici la procédure à suivre :

  1. Spécifiez un emplacement contenant un bouton personnalisé à l'aide de @id/cast_button_type_custom dans l'attribut castControlButtons de ExpandedControllerActivity. Vous pouvez ensuite utiliser getButtonImageViewAt(int) pour obtenir le ImageView correspondant à ce bouton personnalisé.

  2. Implémentez une sous-classe de UIController. UIController contient des méthodes appelées par le SDK lorsque l'état de la session Cast ou de la session multimédia change. Votre sous-classe de UIController doit utiliser ImageView comme paramètre et mettre à jour son état si nécessaire.

  3. Sous-classe ExpandedControllerActivity, puis remplacez onCreate et appeler getButtonImageViewAt(int) pour obtenir l'objet de vue du bouton. Appelez ensuite bindViewToUIController(View, UIController) pour associer la vue à votre UIController personnalisé.

  4. Pour savoir comment gérer l'action à partir de votre bouton personnalisé, consultez MediaIntentReceiver sur la page Ajouter des actions personnalisées.

Voici un exemple d'association d'un bouton à l'emplacement 2 à un UIController appelé 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);
        ...
    }
}