Personaliza la IU de Android Sender

Puedes personalizar los widgets de Cast mediante la configuración de los colores, el estilo de los botones, el texto y la apariencia de la miniatura, y seleccionando los tipos de botones que quieres mostrar.

Cómo personalizar el tema de la app

En este ejemplo, se crea un estilo de tema personalizado Theme.CastVideosTheme que puede definir colores personalizados, un estilo de superposición introductoria, un estilo de controlador en miniatura y un estilo de controlador expandido.

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

Las últimas tres líneas anteriores te permiten definir estilos específicos para la superposición introductoria, el controlador mini y el controlador expandido como parte de este tema. En las siguientes secciones, se incluyen ejemplos.

Personaliza el botón de Cast

Para agregar un mediaRouteTheme personalizado al tema de tu app, haz lo siguiente:

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

Declara tu tema personalizado de Media Router y declara un mediaRouteButtonStyle personalizado:

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

Se debe usar setTint si la versión de la biblioteca de compatibilidad es posterior a la 26.0.0. Para versiones anteriores de la biblioteca de compatibilidad, usa buttonTint en su lugar.

Cómo personalizar el tema de la superposición introductoria

La clase IntroductoryOverlay admite varios atributos de diseño que tu app puede anular en un tema personalizado. En este ejemplo, se muestra cómo anular el aspecto del texto del botón y el título sobre el widget superpuesto:

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

Cómo personalizar el minicontrol

Personalizar tema

La clase MiniControllerFragment admite varios atributos de diseño que tu app puede anular en un tema personalizado. En este ejemplo, se muestra cómo habilitar la visualización de la imagen de miniatura, anular la apariencia del texto del subtítulo y los subtítulos, establecer los colores y personalizar los botones:

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

Elige los botones

Un MiniControllerFragment tiene tres ranuras que pueden mostrar la carátula del álbum y dos botones, o tres botones de control si no se propaga la carátula del álbum.

SLOT  SLOT  SLOT
  1     2     3

De forma predeterminada, el fragmento muestra un botón de activación/desactivación de reproducción/pausa. Los desarrolladores pueden usar el atributo castControlButtons para anular qué botones mostrar. Los botones de control admitidos se definen como recursos de ID:

Tipo de botón Descripción
@id/cast_button_type_empty No coloques un botón en esta ranura
@id/cast_button_type_custom Botón personalizado
@id/cast_button_type_play_pause_toggle Alterna entre la reproducción y la pausa.
@id/cast_button_type_skip_previous Salta al elemento anterior de la fila.
@id/cast_button_type_skip_next Salta al siguiente elemento de la fila.
@id/cast_button_type_rewind_30_seconds Retrocede la reproducción 30 segundos.
@id/cast_button_type_forward_30_seconds Avanza la reproducción 30 segundos
@id/cast_button_type_mute_toggle Silencia y activa el receptor
@id/cast_button_type_closed_caption Abre un diálogo para seleccionar pistas de audio y texto.

A continuación, se muestra un ejemplo en el que se usaría la portada del álbum, un botón de activación para reproducir/pausar y un botón para avanzar en ese orden de izquierda a derecha:

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

Advertencia: Este array debe contener exactamente tres elementos; de lo contrario, se arrojará una excepción de tiempo de ejecución. Si no quieres mostrar un botón en un espacio, usa @id/cast_button_type_empty.

Cómo agregar botones personalizados

Un MiniControllerFragment admite la adición de botones de control personalizados que el SDK no proporciona, como un botón de “me gusta”. Estos son los pasos:

  1. Especifica un espacio para contener un botón personalizado con @id/cast_button_type_custom en el atributo castControlButtons de MiniControllerFragment.

  2. Implementa una subclase de UIController. UIController contiene métodos a los que llama el SDK cuando cambia el estado de la sesión de transmisión o la sesión multimedia. Tu subclase de UIController debe tomar un ImageView como uno de los parámetros y actualizar su estado según sea necesario.

  3. Crea una subclase de MiniControllerFragment, luego anula onCreateView y llama a getButtonImageViewAt(int) para obtener el ImageView de ese botón personalizado. Luego, llama a bindViewToUIController(View, UIController) para asociar la vista con tu UIController personalizado.

  4. Consulta MediaIntentReceiver en Agrega acciones personalizadas para obtener información sobre cómo controlar la acción desde tu botón personalizado.

    Este es un ejemplo de cómo asociar un botón en la ranura 2 a un UIController llamado 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);
        ...
    }
}

Cómo personalizar el controlador expandido

Personalizar tema

Si la actividad de un controlador expandido usa una barra de herramientas de tema oscuro, puedes configurar un tema en la barra de herramientas para usar texto claro y un color de ícono claro:

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

Puedes especificar tus propias imágenes que se usan para dibujar los botones en el controlador expandido:

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

Elige los botones

La actividad del controlador expandido tiene cinco ranuras para mostrar los botones de control. La ranura del medio siempre muestra un botón de activación de reproducción/pausa y no se puede configurar. La app del remitente puede configurar los otros cuatro segmentos, de izquierda a derecha.

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

De forma predeterminada, la actividad muestra un botón de subtítulos, un botón para omitir al elemento anterior, un botón para omitir al elemento siguiente y un botón de activación/desactivación de sonido en estos cuatro espacios, de izquierda a derecha. Los desarrolladores pueden usar el atributo castControlButtons para anular qué botones mostrar en qué posiciones. La lista de botones de control compatibles se define como recursos de ID idénticos a los tipos de botones para los botones del controlador en miniatura.

Este es un ejemplo que coloca un botón de rebobinado en la segunda ranura, un botón de omisión hacia adelante en la tercera ranura y deja el primer y último espacio vacíos:

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

El array debe contener exactamente cuatro elementos; de lo contrario, se arrojará una excepción de tiempo de ejecución. Si no quieres mostrar un botón en un espacio, usa @id/cast_button_type_empty. CastContext puede administrar el ciclo de vida y la presentación de esta actividad.

Cómo agregar botones personalizados

Un ExpandedControllerActivity admite la adición de botones de control personalizados que no proporciona el SDK, como un botón de "me gusta". Estos son los pasos:

  1. Especifica un espacio para contener un botón personalizado con @id/cast_button_type_custom en el atributo castControlButtons de ExpandedControllerActivity. Luego, puedes usar getButtonImageViewAt(int) para obtener el ImageView de ese botón personalizado.

  2. Implementa una subclase de UIController. UIController contiene métodos a los que llama el SDK cuando cambia el estado de la sesión de transmisión o de la sesión multimedia. Tu subclase de UIController debe tomar un ImageView como uno de los parámetros y actualizar su estado según sea necesario.

  3. Crea una subclase de ExpandedControllerActivity y, luego, anula onCreate y llama a getButtonImageViewAt(int) para obtener el objeto de vista del botón. Luego, llama a bindViewToUIController(View, UIController) para asociar la vista con tu UIController personalizado.

  4. Consulta MediaIntentReceiver en Cómo agregar acciones personalizadas para obtener información sobre cómo controlar la acción desde tu botón personalizado.

Este es un ejemplo de cómo asociar un botón en la ranura 2 a un UIController llamado 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);
        ...
    }
}