É possível personalizar os widgets do Google Cast configurando as cores, estilizando os botões, o texto e a aparência das miniaturas e escolhendo os tipos de botões que serão mostrados.
Personalizar tema do app
O exemplo abaixo cria um estilo de tema personalizado Theme.CastVideosTheme
, que
pode definir cores personalizadas, um estilo introdutório de sobreposição, um estilo de minicontrole
e um estilo de controle 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>
As três últimas linhas acima permitem definir estilos específicos para a sobreposição introdutória, o minicontrole e o controle expandido como parte do tema. Confira exemplos nas seções a seguir.
Personalizar o botão Transmitir
Para adicionar um mediaRouteTheme
personalizado ao tema do app:
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- ... -->
<item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
</style>
Declare seu tema de roteador de mídia personalizado e declare um 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>
setTint
será usado se a versão da Biblioteca de Suporte for mais recente que a 26.0.0. Para versões
mais antigas da Biblioteca de Suporte, use
buttonTint
.
Personalizar o tema de sobreposição introdutório
A classe
IntroductoryOverlay
oferece suporte a vários atributos de estilo que o app pode substituir em um tema
personalizado. Este exemplo mostra como substituir a aparência do texto do botão
e do título no widget de sobreposição:
<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>
Personalizar minicontrole
Personalizar tema
A classe
MiniControllerFragment
oferece suporte a vários atributos de estilo que o app pode substituir em um tema
personalizado. Este exemplo mostra como ativar a exibição da imagem em miniatura para
substituir a aparência do texto do subtítulo e da legenda oculta, definir
as cores e personalizar os botões:
<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>
Escolher botões
Um MiniControllerFragment
tem três slots que podem exibir a arte do álbum
e dois botões, ou três botões de controle se a arte do álbum não estiver preenchida.
SLOT SLOT SLOT
1 2 3
Por padrão, o fragmento mostra um botão de alternância para reproduzir/pausar. Os desenvolvedores podem usar
o atributo castControlButtons
para substituir quais botões serão mostrados.
Os botões de controle compatíveis são definidos como
recursos de código:
Tipo de botão | Descrição |
---|---|
@id/cast_button_type_empty |
Não coloque um botão nesse slot |
@id/cast_button_type_custom |
Botão personalizado |
@id/cast_button_type_play_pause_toggle |
Alterna entre a reprodução e a pausa |
@id/cast_button_type_skip_previous |
Pula para o item anterior na fila |
@id/cast_button_type_skip_next |
Pula para o próximo item da fila |
@id/cast_button_type_rewind_30_seconds |
Retrocede a reprodução em 30 segundos |
@id/cast_button_type_forward_30_seconds |
Avançar a reprodução em 30 segundos |
@id/cast_button_type_mute_toggle |
Desativa e ativa o som do destinatário |
@id/cast_button_type_closed_caption |
Abre uma caixa de diálogo para selecionar faixas de texto e áudio |
Confira um exemplo que usa a arte do álbum, um botão ativar/pausar e um botão "Pular para a frente" nessa ordem, da esquerda para a direita:
<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">
Aviso: essa matriz precisa conter exatamente três itens. Caso contrário, uma exceção de
tempo de execução será gerada. Se você não quiser mostrar um botão em um slot, use
@id/cast_button_type_empty
.
Adicionar botões personalizados
Um MiniControllerFragment
oferece suporte à adição de botões de controle personalizados que
não são fornecidos pelo SDK, como um botão "Gostei". Essas etapas são:
Especifique um slot para conter um botão personalizado usando
@id/cast_button_type_custom
no atributocastControlButtons
doMiniControllerFragment
.Implemente uma subclasse de
UIController
. OUIController
contém métodos que são chamados pelo SDK quando o estado da sessão de transmissão ou da sessão de mídia muda. A subclasse deUIController
precisa usar umImageView
como um dos parâmetros e atualizar o estado conforme necessário.Crie uma subclasse
MiniControllerFragment
, substituaonCreateView
e chamegetButtonImageViewAt(int)
para receber oImageView
para esse botão personalizado. Em seguida, chamebindViewToUIController(View, UIController)
para associar a visualização àUIController
personalizada.Consulte
MediaIntentReceiver
em Adicionar ações personalizadas para saber como processar a ação do botão personalizado.Confira um exemplo de associação de um botão no slot 2 a um
UIController
chamadoMyCustomUIController
:
// 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>
// 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) ... } }
// 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); ... } }
Personalizar controle expandido
Personalizar tema
Se a atividade de um controle expandido usar uma barra de ferramentas de tema escuro, você poderá definir um tema nessa barra para usar texto claro e uma cor de ícone clara:
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="castExpandedControllerToolbarStyle">
@style/ThemeOverlay.AppCompat.Dark.ActionBar
</item>
</style>
É possível especificar suas próprias imagens usadas para desenhar os botões no controle 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>
Escolher botões
A atividade do controle expandido tem cinco slots para mostrar os botões de controle. O slot do meio sempre mostra um botão ativar/pausar e não é configurável. Os outros quatro slots podem ser configurados, da esquerda para a direita, pelo app remetente.
SLOT SLOT PLAY/PAUSE SLOT SLOT
1 2 BUTTON 3 4
Por padrão, a atividade mostra um botão de legenda, um botão para pular para o
item anterior, um botão para pular para o próximo item e um botão de ativar o som
nesses quatro slots, da esquerda para a direita. Os desenvolvedores podem usar o
atributo castControlButtons
para substituir quais botões serão mostrados em
cada slot. A lista de botões de controle compatíveis é definida como
recursos de ID idênticos aos
tipos de botões para minicontroles.
Veja um exemplo que coloca um botão "Voltar" no segundo slot e um "Pular" para frente no terceiro slot, deixando o primeiro e o último slots vazios:
// 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>
A matriz precisa conter exatamente quatro itens. Caso contrário, uma exceção de tempo de execução será
gerada. Se você não quiser mostrar um botão em um slot, use
@id/cast_button_type_empty
. CastContext
pode gerenciar o ciclo de vida e
a apresentação dessa atividade.
Adicionar botões personalizados
Um ExpandedControllerActivity
oferece suporte à adição de botões de controle personalizados que não são fornecidos pelo SDK,
como um botão "Gostei". Essas etapas são:
Especifique um slot para conter um botão personalizado usando
@id/cast_button_type_custom
no atributocastControlButtons
doExpandedControllerActivity
. Você pode usargetButtonImageViewAt(int)
para acessar oImageView
desse botão personalizado.Implemente uma subclasse de
UIController
.UIController
contém métodos que são chamados pelo SDK quando o estado da sessão de transmissão ou da sessão de mídia muda. A subclasse deUIController
precisa usar umImageView
como um dos parâmetros e atualizar o estado conforme necessário.Crie uma subclasse ExpandControllerActivity, substitua
onCreate
e chamegetButtonImageViewAt(int)
para conseguir o objeto de visualização do botão. Em seguida, chamebindViewToUIController(View, UIController)
para associar a visualização aoUIController
personalizado.Consulte
MediaIntentReceiver
em Adicionar ações personalizadas para saber como processar a ação do botão personalizado.
Confira um exemplo de associação de um botão no slot 2 a um
UIController
chamado 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>
// 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) ... } }
// 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); ... } }