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

يمكنك تخصيص التطبيقات المصغّرة للإرسال من خلال ضبط الألوان وتصميم الأزرار والنص ومظهر الصورة المصغّرة واختيار أنواع الأزرار التي تريد عرضها.

تخصيص مظهر التطبيق

ينشئ هذا المثال نمط مظهر مخصّص 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

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