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

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 specyficznych dla nakładki wprowadzającej, minikontrolera i rozszerzonego kontrolera w ramach tego motywu. Przykłady znajdziesz w dalszej części tego artykułu.

Dostosowywanie przycisku przesyłania

Aby dodać niestandardowy 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 element: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 należy używać, jeśli wersja biblioteki pomocy jest nowsza niż 26.0.0. W przypadku starszych wersji biblioteki pomocy użyj buttonTint.

Dostosowywanie motywu nakładki wprowadzającej

Klasa IntroductoryOverlay obsługuje różne atrybuty stylu, które aplikacja może zastąpić w niestandardowym motywie. 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

Dostosowanie motywu

Klasa MiniControllerFragment obsługuje różne atrybuty stylu, które aplikacja może zastąpić w niestandardowym motywie. Ten przykład pokazuje, jak włączyć wyświetlanie miniatury, zastąpić wygląd tekstu podtytułu 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

MiniControllerFragment ma 3 miejsca, w których może 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. Programiści 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 w tym miejscu przycisku
@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 Przejście do poprzedniego elementu w kolejce
@id/cast_button_type_skip_next Przejście do następnego elementu w kolejce
@id/cast_button_type_rewind_30_seconds Cofa odtwarzanie o 30 sekund.
@id/cast_button_type_forward_30_seconds Przewija odtwarzanie o 30 sekund do przodu
@id/cast_button_type_mute_toggle Wycisza i włącza odbiornik
@id/cast_button_type_closed_caption Otwiera okno wyboru ścieżek tekstowych i audio.

Oto przykład, w którym w kolejności od lewej do prawej użyto okładki albumu, przycisku przełączania odtwarzania/wstrzymywania i przycisku 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 docelowym, użyj kodu @id/cast_button_type_empty.

Dodawanie niestandardowych przycisków

MiniControllerFragment umożliwia dodawanie niestandardowych przycisków sterujących, które nie są dostępne w pakiecie SDK, np. przycisku „Lubię to”. Kroki:

  1. Określ miejsce na przycisk niestandardowy, używając elementu @id/cast_button_type_custom w atrybucie castControlButtons elementu MiniControllerFragment.

  2. Zaimplementuj podklasę klasy UIController. Interfejs UIController zawiera metody wywoływane przez pakiet SDK, gdy zmieni się stan sesji przesyłania lub sesji multimedialnej. Podklasa UIController powinna przyjmować jako jeden z parametrów wartość ImageView 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 niestandardowego przycisku. Następnie wywołaj bindViewToUIController(View, UIController) funkcję, aby powiązać widok z niestandardowym UIController.

  4. Więcej informacji o obsłudze działania z poziomu przycisku niestandardowego znajdziesz MediaIntentReceiver w artykule Dodawanie działań niestandardowych.

    Oto przykład przypisywania przycisku w slocie 2 do elementu 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 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 rozwiniętym 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

Rozwinięty kontroler ma 5 miejsc na przyciski sterujące. Środkowe miejsce zawsze zawiera przycisk przełączania odtwarzania i wstrzymywania i nie można go skonfigurować. Pozostałe 4 miejsca są konfigurowane od lewej do prawej przez aplikację nadawcy.

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

Domyślnie w tych 4 miejscach od lewej do prawej wyświetlają się przycisk napisów, przycisk przejścia do poprzedniego elementu, przycisk przejścia do następnego elementu i przycisk przełączania wyciszenia. Deweloperzy mogą używać 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 mini kontrolera.

Oto przykład, w którym przycisk przewijania do tyłu znajduje się w drugim slocie, przycisk przewijania do przodu w trzecim slocie, a pierwszy i ostatni slot 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 docelowym, użyj kodu @id/cast_button_type_empty. CastContext może zarządzać cyklem życia i sposobem prezentacji tej aktywności.

Dodawanie niestandardowych przycisków

ExpandedControllerActivity umożliwia dodawanie niestandardowych przycisków sterujących, które nie są dostępne w pakiecie SDK, np. przycisku „Lubię to”. Kroki:

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

  2. Zaimplementuj podklasę klasy UIController. UIController zawiera metody wywoływane przez pakiet SDK, gdy zmieni 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 funkcję bindViewToUIController(View, UIController) aby powiązać widok z niestandardowym UIController.

  4. MediaIntentReceiver Więcej informacji o obsłudze działania z niestandardowego przycisku znajdziesz w sekcji Dodawanie działań niestandardowych.

Oto przykład przypisania przycisku w slocie 2 do elementu 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);
        ...
    }
}