自定义 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>

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

自定义投放按钮

如需向应用的主题添加自定义 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 有 5 个槽位用于显示控件按钮。中间槽位始终显示“播放/暂停”切换按钮,且不可配置。其他四个槽位由发送方应用从左到右配置。

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>

该数组必须正好包含四个项,否则系统会抛出运行时异常。如果您不想在槽位中显示按钮,请使用 @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. 为 ExpandControllerActivity 创建子类,然后替换 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);
        ...
    }
}