Dostosowanie interfejsu nadawcy w Androidzie

Widżety przesyłania możesz dostosować, ustawiając kolory, styl przycisków, tekstu i miniatur, a także wybierając typy przycisków, które mają się wyświetlać.

Dostosowywanie motywu aplikacji

W tym przykładzie tworzymy styl motywu niestandardowego Theme.CastVideosTheme, który może definiować niestandardowe kolory, styl wprowadzającego nakładki, styl sterowania mini oraz styl sterowania rozszerzonego.

<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 dotyczących wprowadzającego nakładki, sterownika mini i rozwiniętego sterownika w ramach tego motywu. Przykłady znajdziesz w następnych sekcjach.

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 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żyć, jeśli wersja biblioteki pomocniczej jest nowsza niż 26.0.0. W przypadku starszych wersji biblioteki pomocy użyj zamiast tego funkcji buttonTint.

Dostosowywanie motywu nakładki powitalnej

Klasa IntroductoryOverlay obsługuje różne atrybuty stylu, które aplikacja może zastąpić w ramach niestandardowego motywu. Ten przykład pokazuje, jak zastąpić wygląd tekstu przycisku 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 ramach niestandardowego motywu. Ten przykład pokazuje, jak włączyć wyświetlanie miniatury, aby zastąpić wygląd tekstu zarówno nagłówka, 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świetlić okładkę albumu, oraz 2 przyciski. Jeśli okładka albumu nie jest wypełniona, element ma 3 przyciski.

SLOT  SLOT  SLOT
  1     2     3

Domyślnie fragment zawiera przycisk odtwarzania/wstrzymywania. Programiści mogą użyć atrybutu castControlButtons, aby zastąpić przyciski, które mają się wyświetlać. 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 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 o 30 sekund,
@id/cast_button_type_forward_30_seconds przewinięcie odtwarzania do przodu o 30 sekund,
@id/cast_button_type_mute_toggle wycisza i włącza mikrofon odbiornika.
@id/cast_button_type_closed_caption Otwiera okno, w którym można wybrać tekst i ścieżki audio

Oto przykład, w którym od lewej do prawej strony 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: tablica musi zawierać dokładnie 3 elementy, w przeciwnym razie zostanie rzucony wyjątek czasu wykonywania. 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ą udostępniane przez pakiet SDK, takich jak przycisk „kciuk w górę”. Kroki:

  1. W atrybucie castControlButtons elementu MiniControllerFragment wskaż slot, który ma zawierać przycisk niestandardowy, używając do tego parametru @id/cast_button_type_custom.

  2. Zaimplementuj podklasę funkcji UIController. Obiekt UIController zawiera metody wywoływane przez pakiet SDK, gdy zmienia się stan sesji przesyłania lub sesji multimediów. Podklasa klasy UIController powinna przyjmować jako jeden z parametrów obiekt ImageView i w razie potrzeby aktualizować jego stan.

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

  4. Informacje o tym, jak obsługiwać działanie z niestandardowego przycisku, znajdziesz w sekcji Dodawanie działań niestandardowych (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

Dostosowanie motywu

Jeśli w rozwiniętym kontrolerze w sekcji Aktywność jest używany pasek narzędzi w ciemnym motywie, możesz ustawić motyw na pasku narzędzi, aby używać jasnego tekstu i jasnych kolorów ikon:

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

Możesz podać 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. W środkowym slocie zawsze wyświetla się przycisk odtwarzania/pauzowania i nie można go konfigurować. Pozostałe 4 miejsca są konfigurowalne 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 pominięcia poprzedniego elementu, przycisk pominięcia następnego elementu oraz przycisk wyciszenia. Deweloperzy mogą użyć atrybutu castControlButtons, aby zastąpić przyciski wyświetlane w danych slotach. Lista obsługiwanych przycisków sterujących jest definiowana jako identyfikatory zasobów identyczne z typami przycisków w przypadku mini kontrolerów.

Oto przykład, w którym w drugim polu znajduje się przycisk przewijania wstecz, w trzecim polu przycisk przewijania do przodu, a pierwsze i ostatnie pole pozostają 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 rzucony wyjątek czasu wykonywania. 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ą udostępniane przez pakiet SDK, takich jak przycisk „kciuk w górę”. Kroki:

  1. W atrybucie castControlButtons elementu ExpandedControllerActivity wskaż slot, który ma zawierać przycisk niestandardowy, używając do tego parametru @id/cast_button_type_custom. Następnie możesz użyć zmiennej getButtonImageViewAt(int), aby uzyskać wartość zmiennej ImageView, która odpowiada temu niestandardowemu przyciskowi.

  2. Zaimplementuj podklasę funkcji UIController. UIController zawiera metody wywoływane przez pakiet SDK, gdy zmienia się stan sesji przesyłania lub sesji multimediów. Podklasa UIController powinna przyjmować ImageView jako jeden z parametrów i w razie potrzeby aktualizować jej stan.

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

  4. Aby dowiedzieć się, jak obsługiwać działanie z niestandardowego przycisku, zapoznaj się z artykułem Dodawanie działań niestandardowych (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);
        ...
    }
}