自定义 Android 发送者界面

您可以通过设置颜色、设置按钮、文本和缩略图外观的样式以及选择要显示的按钮类型来自定义 Cast widget

自定义应用主题

此示例创建了一个自定义主题样式 Theme.CastVideosTheme,它可定义自定义颜色、介绍性叠加层样式、迷你控制器样式和展开控制器样式。

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

通过上面的最后三行代码,您可以将介绍性叠加层、迷你控制器和展开控制器的专属样式定义为此主题的一部分。后续部分提供了相关示例。

自定义投放按钮

如需向应用的 Theme 添加自定义 mediaRouteTheme,请执行以下操作:

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

声明自定义媒体路由器主题并声明自定义 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>

如果支持库版本高于 26.0.0,则应使用 setTint。对于旧版支持库,请改用 buttonTint

自定义介绍性叠加层主题

IntroductoryOverlay 类支持应用可在自定义主题中替换的各种样式属性。以下示例展示了如何在叠加层 widget 上替换按钮和标题的文本外观:

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

自定义迷你控制器

自定义主题背景

MiniControllerFragment 类支持应用可在自定义主题中替换的各种样式属性。以下示例展示了如何启用缩略图显示、替换子标题和字幕的文本外观、设置颜色,以及自定义按钮:

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

选择按钮

MiniControllerFragment 有三个用于显示专辑封面的槽位和两个按钮,或者三个控制按钮(如果未填充专辑封面)。

SLOT  SLOT  SLOT
  1     2     3

默认情况下,Fragment 会显示播放/暂停切换按钮。开发者可以使用 castControlButtons 属性来替换要显示的按钮。支持的控制按钮定义为 ID 资源

按钮类型 说明
@id/cast_button_type_empty 请勿在此槽中放置按钮
@id/cast_button_type_custom 自定义按钮
@id/cast_button_type_play_pause_toggle 在播放和暂停之间切换
@id/cast_button_type_skip_previous 跳至队列中的上一项
@id/cast_button_type_skip_next 跳至队列中的下一项
@id/cast_button_type_rewind_30_seconds 将播放快退 30 秒
@id/cast_button_type_forward_30_seconds 快进 30 秒
@id/cast_button_type_mute_toggle 将接收者静音和取消静音
@id/cast_button_type_closed_caption 打开对话框以选择文本和音轨

以下示例将按从左到右的顺序使用专辑封面、播放/暂停切换按钮和快进按钮:

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

警告:此数组必须正好包含三项内容,否则会抛出运行时异常。如果您不想在槽中显示按钮,请使用 @id/cast_button_type_empty

添加自定义按钮

MiniControllerFragment 支持添加 SDK 未提供的自定义控件按钮,例如“我喜欢”按钮。具体步骤包括:

  1. MiniControllerFragmentcastControlButtons 属性中使用 @id/cast_button_type_custom 指定包含自定义按钮的槽位。

  2. 实现 UIController 的子类。UIController 包含在投射会话或媒体会话的状态发生更改时 SDK 调用的方法。您的 UIController 子类应将 ImageView 作为一个参数,并根据需要更新其状态。

  3. 创建 MiniControllerFragment 子类,然后替换 onCreateView 并调用 getButtonImageViewAt(int) 以获取该自定义按钮的 ImageView。然后调用 bindViewToUIController(View, UIController),将该视图与您的自定义 UIController 相关联。

  4. 如需了解如何通过自定义按钮处理操作,请参阅添加自定义操作中的 MediaIntentReceiver

    以下示例展示了如何将槽位 2 上的按钮与名为 MyCustomUIControllerUIController 相关联:

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

自定义展开的控制器

自定义主题背景

如果展开的控制器的 activity 使用深色主题工具栏,您可以在工具栏上设置主题,以使用浅色文本和浅色图标:

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

您可以指定自己的图片,用于在展开的控制器上绘制按钮:

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

选择按钮

展开的控制器的 Activity 有五个槽位,用于显示控件按钮。中间槽位始终显示播放/暂停切换按钮,且不可配置。其他四个槽位由发送器应用从左到右配置。

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

默认情况下,activity 会在这四个槽中从左到右显示字幕按钮、跳至上一项按钮、跳至下一项按钮以及静音切换按钮。开发者可以使用 castControlButtons 属性来替换要在哪些槽位中显示的按钮。支持的控制按钮列表定义为 ID 资源,与迷你控制器按钮的按钮类型完全相同。

以下示例将快退按钮置于第二个槽位,将快进按钮置于第三个槽位,并将第一个槽位和最后一个槽位留空:

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

该数组必须正好包含 4 项内容,否则会抛出运行时异常。如果您不想在槽中显示按钮,请使用 @id/cast_button_type_emptyCastContext 可以管理此 activity 的生命周期和呈现方式。

添加自定义按钮

ExpandedControllerActivity 支持添加 SDK 未提供的自定义控件按钮,例如“我喜欢”按钮。具体步骤包括:

  1. ExpandedControllerActivitycastControlButtons 属性中使用 @id/cast_button_type_custom 指定包含自定义按钮的槽位。然后,您可以使用 getButtonImageViewAt(int) 获取该自定义按钮的 ImageView

  2. 实现 UIController 的子类。UIController 包含在投射会话或媒体会话的状态发生更改时 SDK 调用的方法。UIController 的子类应将 ImageView 作为参数之一,并根据需要更新其状态。

  3. 创建 ExtendedControllerActivity 的子类,然后替换 onCreate 并调用 getButtonImageViewAt(int) 以获取按钮的视图对象。然后调用 bindViewToUIController(View, UIController),将该视图与您的自定义 UIController 相关联。

  4. 如需了解如何处理自定义按钮中的操作,请参阅添加自定义操作中的 MediaIntentReceiver

以下示例展示了如何将槽位 2 上的按钮与名为 MyCustomUIControllerUIController 相关联:

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