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

التعريف بمظهر "أداة توجيه الوسائط" المخصّص والتعريف بـ 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 لزرّ الإجراء المخصّص هذا. بعد ذلك، استخدِم الدالة 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);
        ...
    }
}