Dostosowanie interfejsu nadawcy w Androidzie

Możesz dostosować widżety Cast ustawiając kolory, stylizując przyciski, tekst i wygląd miniatury oraz wybierając typy przycisków do wyświetlania.

Dostosowywanie motywu aplikacji

Ten przykład tworzy niestandardowy styl motywu Theme.CastVideosTheme, który może definiować spersonalizowane kolory, styl nakładki wprowadzającej, styl minikontrolera i styl rozszerzonego kontrolera.

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

Trzy ostatnie wiersze powyżej umożliwiają zdefiniowanie stylów specyficznych dla nakładki wprowadzającej, minikontrolera i rozszerzonego kontrolera w ramach tego motywu. Przykłady znajdziesz w sekcjach poniżej.

Dostosowywanie przycisku Cast

Aby dodać niestandardowy motyw mediaRouteTheme do motywu aplikacji:

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

Zadeklaruj niestandardowy motyw Media Router i niestandardowy styl 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 Jeśli wersja biblioteki pomocy jest nowsza niż 26.0.0, należy użyć funkcji. W przypadku starszych wersji biblioteki pomocy użyj zamiast tego funkcji buttonTint.

Dostosowywanie motywu nakładki wprowadzającej

Klasa IntroductoryOverlay obsługuje różne atrybuty stylu, które aplikacja może zastąpić w motywie niestandardowym. Ten przykład pokazuje, jak zastąpić wygląd tekstu zarówno przycisku, jak i tytułu w widżecie nakładki:

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

Dostosowywanie minikontrolera

Dostosuj motyw

Klasa MiniControllerFragment obsługuje różne atrybuty stylu, które aplikacja może zastąpić w motywie niestandardowym. Ten przykład pokazuje, jak włączyć wyświetlanie miniatury, zastąpić wygląd tekstu zarówno podtytułu, jak i napisów, ustawić kolory oraz dostosować przyciski:

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

Wybierz przyciski

Element MiniControllerFragment ma 3 miejsca, w których można wyświetlać okładkę albumu i 2 przyciski lub 3 przyciski sterujące, jeśli okładka albumu nie jest wypełniona.

SLOT  SLOT  SLOT
  1     2     3

Domyślnie fragment wyświetla przycisk przełączania odtwarzania/wstrzymywania. Deweloperzy mogą użyć atrybutu castControlButtons, aby zastąpić przyciski, które mają być wyświetlane. Obsługiwane przyciski sterujące są zdefiniowane jako zasoby identyfikatorów:

Typ przycisku Opis
@id/cast_button_type_empty Nie umieszczaj przycisku w tym miejscu
@id/cast_button_type_custom Przycisk niestandardowy
@id/cast_button_type_play_pause_toggle Przełącza między odtwarzaniem i wstrzymaniem
@id/cast_button_type_skip_previous Przeskakuje do poprzedniego elementu w kolejce
@id/cast_button_type_skip_next Przeskakuje do następnego elementu w kolejce
@id/cast_button_type_rewind_30_seconds Przewija odtwarzanie o 30 sekund do tyłu
@id/cast_button_type_forward_30_seconds Przeskakuje odtwarzanie o 30 sekund do przodu
@id/cast_button_type_mute_toggle Wycisza i wyłącza wyciszenie odbiornika
@id/cast_button_type_closed_caption Otwiera okno, w którym można wybrać ścieżki tekstowe i audio

Oto przykład, który będzie używać okładki albumu, przycisku przełączania odtwarzania/wstrzymywania i przycisku przeskakiwania do przodu w tej kolejności od lewej do prawej:

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

Ostrzeżenie: ta tablica musi zawierać dokładnie 3 elementy, w przeciwnym razie zostanie zgłoszony wyjątek czasu wykonywania. Jeśli nie chcesz wyświetlać przycisku w danym miejscu, użyj @id/cast_button_type_empty.

Dodawanie przycisków niestandardowych

Element MiniControllerFragment umożliwia dodawanie niestandardowych przycisków sterujących, które nie są udostępniane przez pakiet SDK, np. przycisku „kciuk w górę”. Kroki:

  1. Określ miejsce, w którym ma się znajdować przycisk niestandardowy, używając @id/cast_button_type_custom w atrybucie castControlButtons elementu MiniControllerFragment.

  2. Zaimplementuj podklasę UIController. Klasa UIController zawiera metody, które są wywoływane przez pakiet SDK, gdy zmieni się stan sesji Cast lub sesji multimedialnej. Podklasa UIController powinna przyjmować ImageView jako jeden z parametrów i w razie potrzeby aktualizować jego stan.

  3. Utwórz podklasę MiniControllerFragment, a następnie zastąp onCreateView i wywołaj getButtonImageViewAt(int) aby uzyskać ImageView dla tego przycisku niestandardowego. Następnie wywołaj bindViewToUIController(View, UIController) , aby powiązać widok z niestandardowym elementem UIController.

  4. W sekcji Dodawanie działań niestandardowych znajdziesz informacje o tym, jak obsługiwać działanie z przycisku niestandardowego.MediaIntentReceiver

    Oto przykład powiązania przycisku w miejscu 2 z elementem UIController o nazwie 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);
        ...
    }
}

Dostosowywanie rozszerzonego kontrolera

Dostosuj motyw

Jeśli aktywność rozszerzonego kontrolera używa paska narzędzi z ciemnym motywem, możesz ustawić motyw paska narzędzi, aby używać jasnego tekstu i jasnego koloru ikony:

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

Możesz określić własne obrazy, które będą używane do rysowania przycisków na rozszerzonym kontrolerze:

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

Wybierz przyciski

Aktywność rozszerzonego kontrolera ma 5 miejsc na przyciski sterujące. Środkowe miejsce zawsze wyświetla przycisk przełączania odtwarzania/wstrzymywania i nie można go skonfigurować. Pozostałe 4 miejsca można skonfigurować od lewej do prawej za pomocą aplikacji nadawcy.

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

Domyślnie aktywność wyświetla w tych 4 miejscach od lewej do prawej przycisk napisów, przycisk przeskakiwania do poprzedniego elementu, przycisk przeskakiwania do następnego elementu i przycisk przełączania wyciszenia. Deweloperzy mogą użyć atrybutu castControlButtons, aby zastąpić przyciski, które mają być wyświetlane w poszczególnych miejscach. Lista obsługiwanych przycisków sterujących jest zdefiniowana jako zasoby identyfikatorów identyczne z typami przycisków dla przycisków minikontrolera.

Oto przykład, który umieszcza przycisk przewijania do tyłu w drugim miejscu, przycisk przeskakiwania do przodu w trzecim miejscu, a pierwsze i ostatnie miejsce pozostawia puste:

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

Tablica musi zawierać dokładnie 4 elementy, w przeciwnym razie zostanie zgłoszony wyjątek czasu wykonywania. Jeśli nie chcesz wyświetlać przycisku w danym miejscu, użyj @id/cast_button_type_empty. Klasa CastContext może zarządzać cyklem życia i prezentacją tej aktywności.

Dodawanie przycisków niestandardowych

Element ExpandedControllerActivity umożliwia dodawanie niestandardowych przycisków sterujących, które nie są udostępniane przez pakiet SDK, np. przycisku „kciuk w górę”. Kroki:

  1. Określ miejsce, w którym ma się znajdować przycisk niestandardowy, używając @id/cast_button_type_custom w atrybucie castControlButtons elementu ExpandedControllerActivity. Następnie możesz użyć getButtonImageViewAt(int) , aby uzyskać ImageView dla tego przycisku niestandardowego.

  2. Zaimplementuj podklasę UIController. Klasa UIController zawiera metody, które są wywoływane przez pakiet SDK, gdy zmieni się stan sesji Cast lub sesji multimedialnej. Podklasa UIController powinna przyjmować ImageView jako jeden z parametrów i w razie potrzeby aktualizować jego stan.

  3. Utwórz podklasę ExpandedControllerActivity, a następnie zastąp onCreate i wywołaj getButtonImageViewAt(int) , aby uzyskać obiekt widoku przycisku. Następnie wywołaj bindViewToUIController(View, UIController) , aby powiązać widok z niestandardowym elementem UIController.

  4. W sekcji Dodawanie działań niestandardowych znajdziesz informacje o tym, jak obsługiwać działanie z przycisku niestandardowego za pomocą MediaIntentReceiver.

Oto przykład powiązania przycisku w miejscu 2 z elementem UIController o nazwie 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);
        ...
    }
}