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 styl motywu niestandardowego Theme.CastVideosTheme, który może definiować niestandardowe 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 rozwiniętego 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 Routera 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 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ż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 zawiera przycisk przełączania odtwarzania/wstrzymywania. Programiści mogą użyć atrybutu castControlButtons, aby zastąpić wyświetlane przyciski. 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 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 przewija odtwarzanie o 30 sekund do tyłu;
@id/cast_button_type_forward_30_seconds Przewija 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 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 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 w czasie działania. Jeśli nie chcesz wyświetlać przycisku w miejscu docelowym, użyj kodu @id/cast_button_type_empty.

Dodawanie niestandardowych przycisków

Obiekt 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 @id/cast_button_type_custom w atrybucie castControlButtons elementu MiniControllerFragment.

  2. Zaimplementuj podklasę UIController. Interfejs UIController zawiera metody wywoływane przez pakiet SDK, gdy zmieni się stan sesji przesyłania lub sesji multimedialnej. Twoja 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 niestandardowego przycisku. Następnie wywołaj funkcję bindViewToUIController(View, UIController) aby powiązać widok z niestandardowym UIController.

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

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

Dostosowanie motywu

Jeśli rozwinięty kontroler aktywności korzysta z 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

Rozszerzony kontroler ma 5 miejsc na przyciski sterujące. Środkowe gniazdo zawsze zawiera przycisk przełączania odtwarzania i pauzy i nie można go konfigurować. 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 pomijania do poprzedniego elementu, przycisk pomijania 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 @id/cast_button_type_custom w atrybucie castControlButtons elementu ExpandedControllerActivity. Następnie możesz użyć kodu getButtonImageViewAt(int) do uzyskania kodu ImageView dla tego niestandardowego przycisku.

  2. Zaimplementuj podklasę UIController. 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 obiekt ImageView 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 UIController.

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

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

// 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);
        ...
    }
}