ב-Android 14 (רמת API 34) יש כמה שיפורים בממשקי ה-API של תמונה בתוך תמונה (PiP) שמאפשרים לבצע כמה משימות בו-זמנית. התמיכה ב-PiP נוספה ב-Android 8.0 (רמת API 26), אבל היא לא נתמכה באופן נרחב ב-Android TV, ולא נתמכה בכלל ב-Google TV לפני Android 13. במצב ריבוי משימות בטלוויזיה, אפשר להשתמש במצב PiP כדי להציג שתי אפליקציות נפרדות על המסך: אחת פועלת במסך מלא, והשנייה פועלת במצב PiP. יש דרישות שונות לאפליקציות שפועלות בכל אחד מהמצבים האלה.
כברירת מחדל, האפליקציה במצב PiP מופיעה כשכבת-על מעל האפליקציה במסך מלא. זה דומה מאוד לפעולה הרגילה של תמונה בתוך תמונה ב-Android.
שימו לב: כשמשלבים ריבוי משימות, צריך להצהיר על סוגי השימוש באפליקציה בהתאם להנחיות האיכות של אפליקציית הטלוויזיה.
הפעלת האפליקציה במצב "תמונה בתוך תמונה"
במכשירי טלוויזיה עם Android 14 (רמת API 34) ומעלה, מפעילים את האפליקציה במצב PiP באמצעות קריאה ל-enterPictureInPictureMode(). מכשירי טלוויזיה עם גרסאות קודמות של Android לא תומכים במצב PiP.
דוגמה להטמעת הלוגיקה של כפתור לכניסה למצב "תמונה בתוך תמונה":
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. בנוסף, כשהפעולה מופעלת, יחס הגובה-רוחב של מצב "תמונה בתוך תמונה" מוגדר כך שיתאים ליחס הגובה-רוחב של הסרטון שמופעל.
חשוב להוסיף כותרת וכותרת משנה כדי לספק למשתמש מידע על השימוש הכללי ב-PIP הזה.
הפעלה במקביל לאפליקציות שפועלות במצב PiP
כשהאפליקציה פועלת במסך מלא, יכול להיות שהיא תצטרך להתאים את עצמה לאפליקציות אחרות שפועלות במצב "תמונה בתוך תמונה".
ממשקי API לשמירה על מרחק
במקרים מסוימים, האפליקציה שמוצגת במצב "תמונה בתוך תמונה" עלולה להסתיר רכיבים חשובים בממשק המשתמש של האפליקציה שמוצגת במסך מלא. כדי למנוע את זה, יש ממשקי API שמאפשרים לאפליקציות לזהות רכיבים קריטיים בממשק המשתמש שאסור להסתיר. המערכת מנסה להיענות לבקשות כדי להימנע מכיסוי הרכיבים האלה על ידי שינוי המיקום של חלון ה-PiP.
כדי לציין שלא צריך להציג שכבת-על בתצוגה, משתמשים ב-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, יכולים להיות קטעי משנה שצריך להשאיר בהם אזורים פנויים. אפשר להשתמש ב-API הזה במקרים כאלה.
סוגי שימושים
באפליקציה צריך להצהיר על מאפיין ערך של מטא-נתונים של 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" />