تخصيص واجهة مستخدم 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 بأحد buttons 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 عند تغيُّر حالة جلسة البث أو جلسة الوسائط. يجب أن تأخذ الفئة الفرعية من 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);
        ...
    }
}