يقدّم الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) بعض التحسينات على واجهات برمجة التطبيقات الخاصة بميزة نافذة ضمن النافذة (PiP) للسماح بتنفيذ عدة مهام في الوقت نفسه. على الرغم من أنّ ميزة "نافذة ضمن النافذة" أصبحت متاحة في نظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، لم تكن متاحة على نطاق واسع على Android TV، ولم تكن متاحة على الإطلاق على Google TV قبل الإصدار 13 من نظام التشغيل Android. يستخدم تعدد المهام على التلفزيون وضع "نافذة ضمن النافذة" للسماح بتشغيل تطبيقَين منفصلَين على الشاشة في الوقت نفسه: أحدهما في وضع ملء الشاشة، والآخر في وضع "نافذة ضمن النافذة". تتوفّر متطلبات مختلفة للتطبيقات التي تعمل في أيّ من هذين الوضعين.
ويتمثّل السلوك التلقائي في أنّ تطبيق "نافذة ضمن النافذة" يغطي تطبيق ملء الشاشة، وهو يشبه إلى حد كبير السلوك العادي لميزة "نافذة ضمن النافذة" في Android.
يُرجى العِلم أنّه عند دمج ميزة تعدد المهام، يجب أن يوضّح تطبيقك أنواع الاستخدام وفقًا لإرشادات جودة تطبيقات Android TV.
تشغيل تطبيقك في وضع "نافذة ضمن النافذة"
بالنسبة إلى أجهزة التلفزيون التي تعمل بالإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، شغِّل تطبيقك في وضع "نافذة ضمن النافذة" من خلال استدعاء enterPictureInPictureMode()
. لا تتوافق أجهزة التلفزيون التي تعمل بإصدارات قديمة من Android مع وضع "نافذة ضمن النافذة".
في ما يلي مثال على كيفية تنفيذ منطق زر للدخول إلى وضع "نافذة ضمن النافذة":
Kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) pictureInPictureButton.visibility = if (requireActivity().packageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { pictureInPictureButton.setOnClickListener { val aspectRatio = Rational(view.width, view.height) val params = PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .build() val result = requireActivity().enterPictureInPictureMode(params) } View.VISIBLE } else { View.GONE } }
Java
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (requireActivity().getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { pictureInPictureButton.setVisibility(View.VISIBLE); pictureInPictureButton.setOnClickListener(v -> { Rational aspectRatio = new Rational(view.getWidth(), view.getHeight()); PictureInPictureParams params = new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setTitle("My Streaming App") .setSubtitle("My On-Demand Content") .build(); Boolean result = requireActivity().enterPictureInPictureMode(params); }); } else { pictureInPictureButton.setVisibility(View.GONE); } }
لا تتم إضافة الإجراء إلا إذا كان الجهاز يتضمّن ميزة النظام
FEATURE_PICTURE_IN_PICTURE
. عند تشغيل هذا الإجراء، يتم أيضًا ضبط نسبة العرض إلى الارتفاع في وضع "نافذة ضمن النافذة" لتتطابق مع نسبة العرض إلى الارتفاع للفيديو الذي يتم تشغيله.
احرص على إضافة عنوان وعنوان فرعي لتزويد المستخدم بمعلومات حول الاستخدام العام لهذا الوضع.
التوافق مع التطبيقات التي تعمل في وضع "نافذة ضمن النافذة"
عندما يكون تطبيقك قيد التشغيل كتطبيق بملء الشاشة، قد يحتاج إلى التكيّف مع التطبيقات الأخرى التي تعمل في وضع "نافذة داخل النافذة".
Keep-clear APIs
في بعض الحالات، قد يعرض تطبيق PiP طبقة فوق عناصر مهمة في واجهة المستخدم ضمن تطبيق وضع ملء الشاشة. ولتجنُّب ذلك، تتوفّر واجهات برمجة تطبيقات keep-clear يمكن للتطبيقات استخدامها لتحديد عناصر واجهة المستخدم المهمة التي يجب عدم عرض طبقة فوقها. يحاول النظام الاستجابة للطلبات لتجنُّب تغطية هذه المكوّنات من خلال إعادة ضبط موضع نافذة "نافذة ضمن النافذة".
لتحديد أنّه يجب عدم وضع عرض فوق عرض آخر، استخدِم preferKeepClear
في تنسيق XML كما في المثال التالي:
<TextView
android:id="@+id/important_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:preferKeepClear="true"
android:text="@string/app_name"/>
يمكنك أيضًا تنفيذ ذلك آليًا باستخدام setPreferKeepClear()
:
Kotlin
private lateinit var binding: MyLayoutBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = MyLayoutBinding.inflate(layoutInflater) setContentView(binding.root) binding.importantText.isPreferKeepClear = true }
Java
private MyLayoutBinding binding; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = MyLayoutBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.importantText.setPreferKeepClear(true); }
قد تحتاج أحيانًا إلى إبقاء جزء فقط من View
واضحًا. يمكن استخدام setPreferKeepClearRects()
لتحديد مناطق View
التي لا يجب أن يتم عرضها فوق الفيديو. قد تحتوي واجهات المستخدم التي لا تستخدم View
بشكلٍ أصلي، مثل Flutter وJetpack Compose وWebView، على أقسام فرعية يجب إبقاء المناطق فيها واضحة. ويمكن استخدام واجهة برمجة التطبيقات هذه في هذه الحالات.
أنواع الاستخدام
يجب أن يحدّد تطبيقك سمة قيمة البيانات الوصفية بقيمة
com.google.android.tv.pip.category
تتوافق مع النوع الأساسي أو أنواع الاستخدام لوضع "نافذة ضمن النافذة". يجب أن يحدّد أي <activity>
تم ضبط android:supportsPictureInPicture="true"
له هذه السمة مع قيمة ذات صلة من الجدول أدناه.
لا يُسمح باستخدام أنواع لا تنتمي إلى أي من هذه الفئات، وخاصةً أي تشغيل لمحتوى وسائط، في وضع "نافذة ضمن النافذة" على التلفزيون.
القيمة | الوصف |
---|---|
"communication " |
حالات استخدام التواصل، مثل مكالمات الفيديو أو المكالمات الصوتية |
"smartHome " |
عمليات التكامل مع الأجهزة المنزلية الذكية، مثل أجراس الأبواب أو أجهزة مراقبة الأطفال المتصلة بالإنترنت |
"health " |
حالات الاستخدام المتعلقة بالصحة، مثل تتبُّع اللياقة البدنية أو مراقبة الحالة الصحية |
"ticker " |
حالات استخدام شريط المعلومات، مثل نتائج المباريات الرياضية المباشرة أو الأخبار وأسعار الأسهم |
يتم الفصل بين القيم المتعددة باستخدام شريط عمودي (|
). على سبيل المثال:
<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />