تخصيص واجهة مستخدم Android Sender

يمكنك تخصيص أدوات 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>

عليك تعريف مظهر مخصّص لـ Media Router وتعريف 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 إذا كان إصدار مكتبة الدعم أحدث من 26.0.0. بالنسبة إلى إصدارات مكتبة الدعم الأقدم، يُرجى استخدام 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

يعرض الجزء تلقائيًا زر تبديل بين التشغيل والإيقاف المؤقت. يمكن للمطوّرين استخدام السمة castControlButtons لتحديد الأزرار التي سيتم عرضها. يتم تعريف أزرار التحكّم المتوافقة على أنّها موارد معرّف:

نوع الزر الوصف
@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. حدِّد خانة تحتوي على زر مخصّص باستخدام @id/cast_button_type_custom في السمة castControlButtons الخاصة بالعنصر MiniControllerFragment.

  2. نفِّذ فئة فرعية من UIController. يحتوي UIController على طرق تستدعيها حزمة SDK عند تغيير حالة جلسة البث أو جلسة الوسائط. يجب أن يتضمّن الصف الفرعي من UIController ImageView كأحد المَعلمات، وأن يعدّل حالته حسب الحاجة.

  3. أنشئ فئة فرعية MiniControllerFragment، ثم ألغِ onCreateView واستدعِ getButtonImageViewAt(int) للحصول على ImageView لذلك الزر المخصّص. بعد ذلك، استخدِم الدالة call bindViewToUIController(View, UIController) لربط طريقة العرض بالمعرّف المخصّص UIController.

  4. راجِع MediaIntentReceiver في إضافة إجراءات مخصّصة لمعرفة كيفية التعامل مع الإجراء من الزر المخصّص.

    في ما يلي مثال على ربط زر في الموضع 2 بـ UIController يُسمى 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);
        ...
    }
}

تخصيص وحدة التحكّم الموسَّعة

تخصيص المظهر

إذا كان نشاط وحدة التحكّم الموسّعة يستخدم شريط أدوات بتصميم داكن، يمكنك ضبط تصميم على شريط الأدوات لاستخدام نص بلون فاتح ولون فاتح للرمز:

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

اختيار الأزرار

يحتوي "النشاط" في وحدة التحكّم الموسّعة على خمسة مواضع لعرض أزرار التحكّم. تعرض الخانة الوسطى دائمًا زر تبديل التشغيل/الإيقاف المؤقت ولا يمكن ضبطها. يمكن لتطبيق المرسِل ضبط الخانات الأربع الأخرى من اليسار إلى اليمين.

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

تعرض &quot;شاشة النشاط&quot; تلقائيًا زرًا للترجمة والشرح وزرًا للانتقال إلى العنصر السابق وزرًا للانتقال إلى العنصر التالي وزرًا لتفعيل/إيقاف كتم الصوت في هذه الخانات الأربع، من اليمين إلى اليسار. يمكن للمطوّرين استخدام السمة castControlButtons لتحديد الأزرار التي سيتم عرضها في الخانات. يتم تحديد قائمة أزرار التحكّم المتوافقة كموارد معرّف مماثلة لأنواع أزرار التحكّم المصغّرة.

في ما يلي مثال يضع زر ترجيع في الخانة الثانية وزر تقديم سريع في الخانة الثالثة، مع ترك الخانتَين الأولى والأخيرة فارغتين:

// 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_empty. يمكن أن يدير CastContext دورة حياة هذا النشاط وطريقة عرضه.

إضافة أزرار مخصّصة

يتيح ExpandedControllerActivity إضافة أزرار تحكّم مخصّصة غير متوفّرة في حزمة تطوير البرامج (SDK)، مثل زر "أعجبني". الخطوات كالآتي:

  1. حدِّد خانة تحتوي على زر مخصّص باستخدام @id/cast_button_type_custom في السمة castControlButtons الخاصة بالعنصر ExpandedControllerActivity. يمكنك بعد ذلك استخدام getButtonImageViewAt(int) للحصول على ImageView لذلك الزر المخصّص.

  2. نفِّذ فئة فرعية من UIController. يحتوي UIController على طرق تستدعيها حزمة SDK عند تغيير حالة جلسة البث أو جلسة الوسائط. يجب أن يتضمّن الصف الفرعي من UIController ImageView كأحد المَعلمات، وأن يتم تعديل حالته حسب الحاجة.

  3. أنشئ فئة فرعية من ExpandedControllerActivity، ثم ألغِ onCreate واطلب getButtonImageViewAt(int) للحصول على عنصر العرض الخاص بالزر. بعد ذلك، استخدِم الدالة bindViewToUIController(View, UIController) لربط طريقة العرض بالسمة المخصّصة UIController.

  4. اطّلِع على MediaIntentReceiver في إضافة إجراءات مخصّصة للتعرّف على كيفية التعامل مع الإجراء من الزرّ المخصّص.

في ما يلي مثال على ربط زر في الفتحة الإعلانية 2 بـ UIController باسم 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);
        ...
    }
}