تخصيص واجهة مستخدم 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>

تتيح لكم الأسطر الثلاثة الأخيرة أعلاه تحديد أنماط خاصة بالتراكب التمهيدي ووحدة التحكّم المصغّرة ووحدة التحكّم الموسّعة كجزء من هذا المظهر. تتضمّن الأقسام التالية أمثلة على ذلك.

تخصيص زر Cast

لإضافة 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>

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) عند تغيير حالة جلسة Cast أو جلسة الوسائط. يجب أن تأخذ الفئة الفرعية من UIController عنصر ImageView كأحد المعلّمات وتعدِّل حالته حسب الحاجة.

  3. أنشئوا فئة فرعية من MiniControllerFragment، ثم ألغوا onCreateView واستدعوا getButtonImageViewAt(int) للحصول على ImageView لهذا الزر المخصّص. بعد ذلك، استدعوا 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

تعرض الأداة بشكل تلقائي زر الترجمة والشرح وزر الانتقال إلى العنصر السابق وزر الانتقال إلى العنصر التالي وزر تبديل كتم الصوت في هذه المساحات الأربع من اليمين إلى اليسار. يمكن للمطوّرين استخدام السمة 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) عند تغيير حالة جلسة Cast أو جلسة الوسائط. يجب أن تأخذ الفئة الفرعية من 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);
        ...
    }
}