自定义 Android 发送者界面

您可以通过以下方式自定义 Cast 微件:设置颜色;设置按钮、文字和缩略图外观样式;选择要显示的按钮类型。

自定义应用主题

此示例创建了一个自定义主题样式 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>

声明自定义 MediaRouter 主题并声明自定义 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 类支持各种样式属性,您的应用可以在自定义主题中替换这些属性。以下示例展示了如何替换叠加层微件上按钮和标题的文本外观:

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

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