Dostosowanie interfejsu nadawcy w Androidzie

Możesz dostosować widżety przesyłania, ustawiając kolory, styl przycisków, tekstu i miniatur oraz wybierając typy przycisków do wyświetlenia.

Dostosowywanie motywu aplikacji

W tym przykładzie tworzymy niestandardowy styl motywu Theme.CastVideosTheme, który może definiować spersonalizowane kolory, styl nakładki wprowadzającej, styl minikontrolera i styl rozwiniętego 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>

Ostatnie 3 wiersze powyżej umożliwiają zdefiniowanie stylów nakładki wprowadzającej, miniodtwarzacza i rozszerzonego odtwarzacza w ramach tego motywu. Przykłady znajdziesz w sekcjach poniżej.

Dostosowywanie przycisku Cast

Aby dodać niestandardowy element 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 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>

Jeśli wersja biblioteki pomocy jest nowsza niż 26.0.0, należy użyć setTint. W przypadku starszych wersji biblioteki obsługi użyj buttonTint.

Dostosowywanie motywu nakładki powitalnej

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 przycisku i tytułu nad widżetem 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 miniodtwarzacza

Dostosowanie motywu

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 podtytułu i napisów, ustawić kolory i 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

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żywać 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 a wstrzymaniem.
@id/cast_button_type_skip_previous Przechodzi do poprzedniego elementu w kolejce.
@id/cast_button_type_skip_next Przechodzi do następnego elementu w kolejce
@id/cast_button_type_rewind_30_seconds Przewija odtwarzanie do tyłu o 30 sekund
@id/cast_button_type_forward_30_seconds Przewija odtwarzanie do przodu o 30 sekund
@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, w którym od lewej do prawej strony wyświetlane są: okładka albumu, przycisk przełączania odtwarzania/wstrzymania i przycisk przewijania do przodu:

<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 działania. Jeśli nie chcesz wyświetlać przycisku w miejscu, użyj @id/cast_button_type_empty.

Dodawanie przycisków niestandardowych

MiniControllerFragment obsługuje dodawanie niestandardowych przycisków sterowania, które nie są dostępne w pakiecie SDK, np. przycisku „kciuk w górę”. Kroki:

  1. Określ boks, który ma zawierać przycisk niestandardowy, używając @id/cast_button_type_custom w atrybucie castControlButtons elementu MiniControllerFragment.

  2. Zaimplementuj podklasę UIController. UIController zawiera metody wywoływane przez pakiet SDK, gdy zmienia się stan sesji przesyłania lub sesji multimedialnej. Podklasa UIController powinna przyjmować ImageView jako jeden z parametrów i w razie potrzeby aktualizować swój 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 UIController.

  4. Informacje o tym, jak obsłużyć działanie niestandardowego przycisku, znajdziesz w sekcji MediaIntentReceiver w artykule Dodawanie działań niestandardowych.

    Oto przykład powiązania przycisku w gnieździe 2 z 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 rozwiniętego kontrolera

Dostosowanie motywu

Jeśli aktywność rozwiniętego kontrolera używa paska narzędzi z ciemnym motywem, możesz ustawić motyw na pasku 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. Środkowy boks zawsze wyświetla przycisk przełączania odtwarzania/wstrzymania i nie można go skonfigurować. Pozostałe 4 miejsca (od lewej do prawej) może skonfigurować aplikacja nadawcy.

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

Domyślnie w tych 4 miejscach aktywność wyświetla (od lewej do prawej) przycisk napisów, przycisk przejścia do poprzedniego elementu, przycisk przejścia do następnego elementu i przycisk wyciszenia. Deweloperzy mogą używać atrybutu castControlButtons, aby zastąpić przyciski wyświetlane w poszczególnych boksach. Lista obsługiwanych przycisków sterujących jest zdefiniowana jako zasoby identyfikatorów identyczne z typami przycisków minikontrolera.

Oto przykład, w którym przycisk przewijania do tyłu znajduje się w drugim miejscu, przycisk pomijania do przodu w trzecim, a pierwsze i ostatnie miejsce są 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 działania. Jeśli nie chcesz wyświetlać przycisku w miejscu, użyj @id/cast_button_type_empty. CastContext może zarządzać cyklem życia i prezentacją tej aktywności.

Dodawanie przycisków niestandardowych

ExpandedControllerActivity obsługuje dodawanie niestandardowych przycisków sterowania, które nie są dostępne w pakiecie SDK, takich jak przycisk „kciuk w górę”. Kroki:

  1. Określ boks, który ma zawierać 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. UIController zawiera metody wywoływane przez pakiet SDK, gdy zmienia się stan sesji przesyłania lub sesji multimedialnej. Podklasa UIController powinna przyjmować ImageView jako jeden z parametrów i w razie potrzeby aktualizować swój 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. Aby dowiedzieć się, jak obsługiwać działanie niestandardowego przycisku, zapoznaj się z sekcją MediaIntentReceiver w artykule Dodawanie działań niestandardowych.

Oto przykład powiązania przycisku w gnieździe 2 z 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);
        ...
    }
}