支持多窗口模式

במצב 'חלונות מרובים', כמה אפליקציות יכולות לשתף את אותו מסך בו-זמנית. אפשר להציג אפליקציות זו לצד זו או אחת מעל השנייה (מצב מסך מפוצל), אפליקציה אחת בחלון קטן שמופיע מעל אפליקציות אחרות (מצב 'תמונה בתוך תמונה') או אפליקציות נפרדות בחלונות נפרדים שניתן להזיז ולשנות את הגודל שלהם (מצב חלונות במחשב).

איור 1. הצגת שתי אפליקציות זו לצד זו במצב מסך מפוצל.

הוראות למשתמש לגישה למצב מסך מפוצל בטלפונים מפורטות במאמר הצגת שתי אפליקציות בו-זמנית בטלפון Pixel.

תכונות ספציפיות לגרסה של ריבוי חלונות

חוויית המשתמש בחלונות מרובים תלויה בגרסת Android ובסוג המכשיר:

  • ב-Android 7.0 (רמת API 24) הושק מצב מסך מפוצל במכשירים עם מסך קטן ומצב תמונה בתוך תמונה במכשירים נבחרים.

    • מצב מסך מפוצל ממלא את המסך בשתי אפליקציות, שמוצגות זו לצד זו או אחת מעל השנייה. המשתמשים יכולים לגרור את המחיצה שמפרידה בין שתי האפליקציות כדי להגדיל את האחת ולהקטין את השנייה.

    • מצב 'תמונה בתוך תמונה' מאפשר למשתמשים להמשיך את הפעלת הסרטון תוך כדי אינטראקציה עם אפליקציה אחרת (מידע נוסף זמין במאמר תמיכה בתכונה 'תמונה בתוך תמונה').

    • יצרני מכשירים עם מסך גדול יכולים להפעיל את מצב חלונות במחשב, שבו המשתמשים יכולים לשנות את הגודל של כל פעילות באופן חופשי.

      כדי לקבוע איך האפליקציה תפעל במצב של חלונות מרובים, אפשר לציין את המימדים המינימליים המותרים של הפעילות. אפשר גם להשבית את מצב החלונות המרובים באפליקציה על ידי הגדרת resizeableActivity="false" כדי לוודא שהמערכת תמיד תציג את האפליקציה במסך מלא.

  • ב-Android 8.0 (רמת API 26) אפשר להשתמש במצב 'תמונה בתוך תמונה' במכשירים עם מסך קטן.

  • ב-Android 12 (רמת API ‏31) מצב חלונות מרובים הוא התנהגות רגילה.

    • במסכים גדולים (סיווג גודל חלון בינוני או מורחב), הפלטפורמה תומכת בכל האפליקציות במצב 'כמה חלונות בו-זמנית', ללא קשר להגדרות האפליקציה. אם הערך הוא resizeableActivity="false", האפליקציה מועברת למצב תאימות במקרה הצורך כדי להתאים למימדי המסך.

    • במסכים קטנים (סיווג גודל חלון קומפקטי), המערכת בודקת את minWidth ו-minHeight של הפעילות כדי לקבוע אם אפשר להריץ אותה במצב של כמה חלונות. אם הערך הוא resizeableActivity="false", האפליקציה לא תופעל במצב של כמה חלונות, ללא קשר לרוחב ולגובה המינימליים.

מצב מסך מפוצל

כדי להפעיל את מצב המסך המפוצל, המשתמשים מבצעים את הפעולות הבאות:

  1. פותחים את מסך 'אחרונים'.
  2. מחליקים אפליקציה כדי להציג אותה
  3. לוחצים על סמל האפליקציה בסרגל הכותרת של האפליקציה.
  4. בוחרים באפשרות בתפריט של המסך המפוצל.
  5. בוחרים אפליקציה אחרת במסך 'מהזמן האחרון', או סוגרים את המסך 'מהזמן האחרון' ומפעילים אפליקציה אחרת.

כדי לצאת ממצב מסך מפוצל, המשתמשים גוררים את המחיצה בין החלונות לקצה המסך – למעלה או למטה, שמאלה או ימינה.

הפעלה של חלון סמוך

אם האפליקציה שלכם צריכה לגשת לתוכן דרך כוונה (intent), תוכלו להשתמש ב-FLAG_ACTIVITY_LAUNCH_ADJACENT כדי לפתוח את התוכן בחלון צמוד במסך מפוצל.

FLAG_ACTIVITY_LAUNCH_ADJACENT הוצג ב-Android 7.0 (רמת API ‏24) כדי לאפשר לאפליקציות שפועלות במצב מסך מפוצל להפעיל פעילויות בחלון הסמוך.

ב-Android 12L‏ (רמת API 32) ואילך, ההגדרה של הדגל הורחבה כדי לאפשר לאפליקציות שפועלות במסך מלא להפעיל מצב מסך מפוצל ואז להפעיל פעילויות בחלון הסמוך.

כדי להפעיל פעילות סמוכה, משתמשים ב-FLAG_ACTIVITY_LAUNCH_ADJACENT בשילוב עם FLAG_ACTIVITY_NEW_TASK, לדוגמה:

fun openUrlInAdjacentWindow(url:
String) { Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(url)
addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or Intent.FLAG_ACTIVITY_NEW_TASK)
 }.also { intent -> startActivity(intent) } }

מחזור החיים של פעילות במצב ריבוי חלונות

מצב חלונות מרובים לא משנה את מחזור החיים של הפעילות. עם זאת, המצב של אפליקציות שממשיכות לפעול בכמה חלונות משתנה בגרסאות שונות של Android.

חזרה להקראה בכמה קטעים

בגרסת Android 10 (API ברמה 29) ואילך יש תמיכה בהפעלה מחדש של כמה משימות בו-זמנית – כל הפעילויות נשארות במצב RESUMED כשהמכשיר במצב חלונות מרובים. אפשר להשהות פעילות אם פעילות שקופה מופיעה מעל הפעילות או אם אי אפשר להתמקד בפעילות, למשל אם הפעילות נמצאת במצב תמונה בתוך תמונה. יכול להיות גם שאף פעילות לא תהיה במוקד תשומת הלב בזמן נתון, למשל אם חלונית ההתראות פתוחה. השיטה onStop() פועלת כרגיל: היא נקראת בכל פעם שפעילות מסוימת יוצאת מהמסך.

התכונה 'המשך מספר קטעים בו-זמנית' זמינה גם במכשירים נבחרים עם Android 9 (API ברמה 28). כדי להביע הסכמה לשימוש בהפעלה מחדש בכמה מכשירים במכשירי Android 9, מוסיפים את המטא-נתונים הבאים למניפסט:

<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />

כדי לוודא שמכשיר מסוים תומך במטא-נתונים האלה של המניפסט, צריך לעיין במפרטי המכשיר.

Android 9

במצב 'חלונות מרובים' ב-Android 9 (רמת API 28) ובגרסאות ישנות יותר, רק הפעילות שבה המשתמש ביצע את האינטראקציה האחרונה פעילה בכל זמן נתון. הפעילות הזו נחשבת הפעילות העליונה, והיא הפעילות היחידה בסטטוס RESUMED. כל שאר הפעילויות הגלויות הן STARTED אבל לא RESUMED. עם זאת, המערכת נותנת לפעילויות האלה שגלויות אבל לא הומשכו עדיפות גבוהה יותר מאשר לפעילויות שלא גלויות. אם המשתמש יוצר אינטראקציה עם אחת מהפעילויות הגלויה, הפעילות הזו תתחדש והפעילות שהיתה בראש תעבור למצב STARTED.

כשיש כמה פעילויות בתוך תהליך אפליקציה פעיל אחד, הפעילות עם סדר z הגבוה ביותר ממשיכה והפעילויות האחרות מושהות.

שינויים בהגדרות

כשהמשתמש מעביר אפליקציה למצב חלונות מרובים, המערכת מעדכנת את הפעילות על שינוי בתצורה, כפי שמתואר בקטע טיפול בשינויים בתצורה. המצב הזה מתרחש גם כשהמשתמש משנה את גודל האפליקציה או מחזיר אותה למצב מסך מלא.

באופן מהותי, לשינוי הזה יש את אותן השלכות על מחזור החיים של הפעילות כמו כשהמערכת מעדכנת את האפליקציה שהמכשיר עבר מכיוון לאורך לכיוון לרוחב, אלא שהמידות של האפליקציה משתנות במקום רק להחליף אותן. הפעילות יכולה לטפל בשינוי ההגדרות בעצמה, או שהאפליקציה יכולה לאפשר למערכת למחוק את הפעילות וליצור אותה מחדש עם המאפיינים החדשים.

אם המשתמש משנה את גודל החלון ומגדיל אותו באחת מהמימדים, המערכת משנה את גודל הפעילות בהתאם לפעולה של המשתמש ומנפיקה שינויים בהגדרות לפי הצורך. אם יש עיכוב בציור באזורים שנחשפו לאחרונה, המערכת תמלא את האזורים האלה באופן זמני בצבע שצוין במאפיין windowBackground או במאפיין הסגנון windowBackgroundFallback שמוגדר כברירת מחדל.

גישה בלעדית למשאבים

כדי לתמוך בתכונה 'המשך בכמה קטעים', צריך להשתמש בקריאה החוזרת של מחזור החיים onTopResumedActivityChanged().

פונקציית ה-callback מופעלת כשפעילות מסוימת מקבלת או מאבדת את המיקום העליון של הפעילות שהמשתמשים חזרו אליה. הדבר חשוב כשפעילות משתמשת במשאב יחיד (singleton) משותף, כמו המיקרופון או המצלמה:

override fun
onTopResumedActivityChanged(topResumed: Boolean) { if (topResumed) { // Top
resumed activity. // Can be a signal to re-acquire exclusive resources. } else {
// No longer the top resumed activity. } }

חשוב לזכור שאפליקציה יכולה לאבד משאבים מסיבות אחרות, כמו הסרה של חומרה משותפת.

בכל מקרה, אפליקציה צריכה לטפל באירועים ובשינויים במצב שמשפיעים על המשאבים הזמינים בצורה חלקה.

באפליקציות שמשתמשות במצלמה, CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged() מספק רמז שזה יכול להיות זמן טוב לנסות לקבל גישה למצלמה. השיטה הזו זמינה החל מגרסה 10 של Android (רמת API‏ 29).

חשוב לזכור ש-resizeableActivity=false לא מבטיח גישה בלעדית למצלמה, כי אפשר לפתוח אפליקציות אחרות שמשתמשות במצלמה במסכים אחרים.

איור 2. מצלמה במצב ריבוי חלונות.

האפליקציה לא חייבת לשחרר את המצלמה כשהיא מאבדת את המיקוד. לדוגמה, יכול להיות שתרצו להמשיך את התצוגה המקדימה של המצלמה בזמן שהמשתמש יוצר אינטראקציה עם האפליקציה העליונה ביותר שמופעלת כרגע. אין בעיה שהאפליקציה תמשיך להפעיל את המצלמה כשהיא לא האפליקציה העליונה ביותר שמופעלת כרגע, אבל היא צריכה לטפל כראוי במקרה של ניתוק. כשהאפליקציה העליונה שתמשיכו ממנה תרצה להשתמש במצלמה, היא תוכל לפתוח אותה והאפליקציה שלכם תאבד את הגישה. האפליקציה יכולה לפתוח מחדש את המצלמה כשהיא מקבלת שוב את המיקוד.

אחרי שאפליקציה מקבלת קריאה חוזרת (callback) מסוג CameraDevice.StateCallback#onDisconnected(), קריאות נוספות למכשיר המצלמה יגרמו להשלכת CameraAccessException.

למספר צגים

ב-Android 10 (רמת API‏ 29) יש תמיכה בפעילויות במסכים משניים. אם פעילות מסוימת פועלת במכשיר עם כמה מסכים, המשתמשים יכולים להעביר את הפעילות ממסך אחד למסך אחר. התכונה המשך מרובות רלוונטית גם בתרחישים של מסכים מרובים, שבהם כמה פעילויות יכולות לקבל קלט ממשתמש בו-זמנית.

אפליקציה יכולה לציין באיזה מסך היא צריכה לפעול כשהיא מופעלת או כשהיא יוצרת פעילות אחרת. ההתנהגות הזו תלויה במצב ההפעלה של הפעילות שמוגדר בקובץ המניפסט, ובדגלים ובאפשרויות של הכוונה שהוגדרו על ידי הישות שמפעילה את הפעילות. פרטים נוספים זמינים בכיתה ActivityOptions.

כשפעילות מועברת למסך משני, היא עשויה לעבור עדכון הקשר, שינוי גודל החלון ושינויים בהגדרות ובמשאבים. אם הפעילות מטפלת בשינוי ההגדרה, היא תקבל הודעה ב-onConfigurationChanged(). אחרת, הפעילות תופעל מחדש.

אם הפעילות מטפלת בשינוי ההגדרות, היא צריכה לבדוק את התצוגה הנוכחית ב-onCreate() וב-onConfigurationChanged(). חשוב לעדכן את המשאבים והפריסות כשהתצוגה משתנה.

אם מצב ההפעלה שנבחר לפעילות מאפשר כמה מופעים, הפעלה במסך משני עשויה ליצור מופע חדש של הפעילות. שתי הפעילויות יחודשו בו-זמנית.

איור 3. מספר מופעים של פעילות במספר מסכים.

כדאי גם לקרוא על ממשקי ה-API למסכים מרובים שהוצגו ב-Android 8.0.

פעילות לעומת הקשר של אפליקציה

שימוש בהקשר הנכון הוא קריטי כשמשתמשים בכמה מסכים. כשאתם ניגשים למשאבים, הקשר של הפעילות (שמוצג) שונה מהקשר של האפליקציה (שלא מוצג).

הקשר של הפעילות מכיל מידע על המסך, והוא תמיד מותאם לאזור התצוגה שבו הפעילות מופיעה. כך תוכלו לקבל את המידע הנכון על צפיפות המסך או על מדדי החלון של האפליקציה. תמיד צריך להשתמש בהקשר הפעילות (או בהקשר אחר שמבוסס על ממשק המשתמש) כדי לקבל מידע על החלון או המסך הנוכחיים. השינוי הזה משפיע גם על חלק מממשקי ה-API של המערכת שמשתמשים במידע מההקשר (לדוגמה, סקירה כללית על הודעות Toast).

ההגדרות של חלון הפעילות והתצוגה של ההורה מגדירות את המשאבים וההקשר. כדי לקבל את התצוגה הנוכחית:

val activityDisplay = activity.getDisplay()

הצגת המדדים הנוכחיים של חלון הפעילות:

val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()

אחזור מדדי החלון המקסימלי בהגדרת המערכת הנוכחית:

val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()

מדדי החלון המקסימלי משמשים לביצוע חישובים, לבחירת פריסה או לקביעת גודל המשאבים שאתם רוצים לאחזר מראש. האפשרות הזו ב-onCreate() מאפשרת לכם לקבל את ההחלטות האלה לפני עיבוד הפריסה הראשון. אין להשתמש במדדים האלה כדי לתכנן את הפריסה של רכיבי תצוגה ספציפיים. במקום זאת, צריך להשתמש במידע מהאובייקט Configuration.

מגרעות במסך

למכשירים מתקפלים יכולה להיות גיאומטריה שונה של פתחי החיתוך במצב מקופל ובמצב פתוח. כדי למנוע בעיות שקשורות לחורים במסך, כדאי לעיין במאמר תמיכה בחלקים חתוכים במסך.

מסכים משניים

אפשר לקבל את המסכים הזמינים משירות המערכת DisplayManager:

val displayManager =
getSystemService(Context.DISPLAY_SERVICE) as DisplayManager val displays =
displayManager.getDisplays()

אפשר להשתמש בכיתה Display כדי לקבל מידע על מסך מסוים, כמו גודל המסך או דגלים שמציינים אם המסך מאובטח. עם זאת, אל תניחו שגודל התצוגה יהיה זהה לאזור התצוגה שהוקצה לאפליקציה. חשוב לזכור שבמצב ריבוי חלונות, האפליקציה תופסת חלק מהמסך.

איך בודקים אם אפשר להפעיל פעילות במסך:

val activityManager =
getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val
activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context,
displayId, intent)

לאחר מכן מפעילים את הפעילות במסך:

val options = ActivityOptions.makeBasic()
options.setLaunchDisplayId(targetDisplay.displayId) startActivity(intent,
options.toBundle())

תמיכה במספר מסכים

ב-Android יש תמיכה בתצוגה מרובת מסכים למקלדות תוכנה, למסכי רקע ולמרכזי אפליקציות.

מקלדת שמופיעה במסך

אפשר להציג מקלדת במסך משני אם המסך מוגדר לתמוך בקישוט המערכת. עורך שיטת הקלט מופיע באופן אוטומטי אם שדה טקסט מבקש קלט במסך הזה.

איור 4. מקלדת במסך משני.

טפט

ב-Android 10 (רמת API ‏29), אפשר להגדיר טפט במסכים משניים. המסגרת יוצרת מכונה נפרדת של WallpaperService.Engine לכל תצוגה. חשוב לוודא שהפנים של כל מנוע מצוירים בנפרד. מפתחים יכולים לטעון נכסים באמצעות הקשר התצוגה ב-WallpaperService.Engine#getDisplayContext(). בנוסף, חשוב לוודא שהקובץ WallpaperInfo.xml מגדיר את android:supportsMultipleDisplays="true".

איור 5. טפט בטלפון ובמסך המשני.

מרכזי אפליקציות

קטגוריה חדשה של מסנני כוונה, SECONDARY_HOME, מספקת פעילות ייעודית למסכים משניים. המופעים של הפעילות משמשים בכל המסכים שתומכים בסמלי המערכת, אחד לכל מסך.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

לפעילות צריך להיות מצב הפעלה שלא מונע כמה מופעים ויכול להתאים לגדלים שונים של מסכים. אסור להשתמש באפשרויות singleInstance או singleTask למצב ההפעלה.

לדוגמה, ההטמעה של AOSP ב-Launcher3 תומכת בפעילות SECONDARY_HOME.

איור 6. מרכז אפליקציות בעיצוב חדשני תלת-ממדי בטלפון.
איור 7. מרכז האפליקציות של Material Design במסך משני.

מדדי חלון

ב-Android 11 (רמת API ‏30) הוספנו את השיטות הבאות של WindowManager כדי לספק את גבולות האפליקציות שפועלות במצב ריבוי חלונות:

השיטות computeCurrentWindowMetrics() ו-computeMaximumWindowMetrics() בספריית WindowManager של Jetpack מציעות פונקציונליות דומה, אבל עם תאימות לאחור לגרסה 14 של API.

כדי לקבל מדדים של תצוגות שאינן התצוגה הנוכחית, מבצעים את הפעולות הבאות (כפי שמוצג בקטע הקוד):

  • יצירת הקשר של מודעה לרשת המדיה
  • יצירת הקשר של חלון לתצוגה
  • אחזור הערך של WindowManager בהקשר של החלון
  • אחזור הערך של WindowMetrics של אזור התצוגה המקסימלי שזמין לאפליקציה

val windowMetrics =
context.createDisplayContext(display)
.createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
.getSystemService(WindowManager::class.java) .maximumWindowMetrics

שיטות שהוצאו משימוש

השיטות getSize() ו-getMetrics() של Display הוצאו משימוש ברמת ה-API 30 לטובת השיטות החדשות של WindowManager.

ב-Android 12 (רמת API ‏31) הוצאו משימוש השיטות DisplaygetRealSize() ו-getRealMetrics(), וההתנהגות שלהן עודכנה כדי להתקרב יותר להתנהגות של getMaximumWindowMetrics().

הגדרת מצב ריבוי חלונות

אם האפליקציה שלכם מטרגטת את Android 7.0 (רמת API ‏24) ואילך, תוכלו להגדיר איך הפעילויות באפליקציה תומכות במצב 'חלונות מרובים' ואם הן תומכות בו בכלל. אפשר להגדיר מאפיינים במניפסט כדי לקבוע את הגודל ואת הפריסה. הגדרות המאפיינים של פעילות ברמה הבסיסית חלות על כל הפעילויות בתוך מקבץ המשימות שלה. לדוגמה, אם לפעילות ברמה הבסיסית יש את הערך android:resizeableActivity="true", אפשר לשנות את הגודל של כל הפעילויות ב-task stack. במכשירים גדולים מסוימים, כמו Chromebook, יכול להיות שהאפליקציה תפעל בחלון שניתן לשינוי הגודל גם אם מציינים את הערך android:resizeableActivity="false". אם הפעולה הזו גורמת לשגיאות באפליקציה, תוכלו להשתמש במסננים ב-Google Play כדי להגביל את הזמינות של האפליקציה במכשירים כאלה.

ברירת המחדל של Android 12 (רמת API ‏31) היא מצב ריבוי חלונות. במסכים גדולים (סיווג גודל חלון בינוני או מורחב), כל האפליקציות פועלות במצב חלונות מרובים, ללא קשר להגדרת האפליקציה. במסכים קטנים, המערכת בודקת את ההגדרות minWidth, minHeight ו-resizeableActivity של הפעילות כדי לקבוע אם אפשר להפעיל אותה במצב של חלונות מרובים.

resizeableActivity

כדי להפעיל או להשבית את מצב החלונות המרובים לגרסאות API ברמה 30 ומטה, מגדירים את המאפיין הזה באלמנט <activity> או <application> במניפסט:

<application
  android:name=".MyActivity"
  android:resizeableActivity=["true" | "false"] />;

אם המאפיין הזה מוגדר כ-true, אפשר להפעיל את הפעילות במצב מסך מפוצל ובמצב חלון במחשב. אם המאפיין מוגדר לערך false, לא תהיה תמיכה במצב של חלונות מרובים בפעילות. אם הערך הוא false והמשתמש מנסה להפעיל את הפעילות במצב חלונות מרובים, הפעילות תופסת את המסך המלא.

אם האפליקציה שלכם מטרגטת רמת API 24 ואילך, אבל לא ציינתם ערך למאפיין הזה, ערך ברירת המחדל של המאפיין הוא true.

אם האפליקציה שלכם מטרגטת רמת API ‏31 ואילך, המאפיין הזה פועל באופן שונה במסכים קטנים וגדולים:

  • מסכים גדולים (חלונות בקטגוריית גודל בינוני או מורחב): כל האפליקציות תומכות במצב 'כמה חלונות בו-זמנית'. המאפיין מציין אם אפשר לשנות את הגודל של פעילות. אם הערך הוא resizeableActivity="false", האפליקציה מועברת למצב תאימות כשצריך כדי להתאים למימדי המסך.
  • מסכים קטנים (סיווג גודל חלון קומפקטי): אם resizeableActivity="true" והרוחב והגובה המינימליים של הפעילות עומדים בדרישות של תצוגת חלונות מרובים, הפעילות תומכת במצב של תצוגת חלונות מרובים. אם הערך הוא resizeableActivity="false", הפעילות לא תומכת במצב של חלונות מרובים, ללא קשר לרוחב ולגובה המינימליים של הפעילות.

supportsPictureInPicture

מגדירים את המאפיין הזה בצומת <activity> במניפסט כדי לציין אם הפעילות תומכת במצב 'תמונה בתוך תמונה'.

<activity
  android:name=".MyActivity"
  android:supportsPictureInPicture=["true" | "false"] />

configChanges

כדי לטפל בעצמכם בשינויים בהגדרות של חלונות מרובים, למשל כשמשתמש משנה את גודל החלון, מוסיפים את המאפיין android:configChanges לצומת <activity> במניפסט של האפליקציה עם לפחות את הערכים הבאים:

<activity
  android:name=".MyActivity"
  android:configChanges="screenSize | smallestScreenSize
      | screenLayout | orientation" />

אחרי שמוסיפים את android:configChanges, הפעילות והקטעים מקבלים קריאה חוזרת (callback) ל-onConfigurationChanged() במקום להימחק ולהיווצר מחדש. לאחר מכן תוכלו לעדכן את התצוגות באופן ידני, לטעון מחדש את המשאבים ולבצע פעולות אחרות לפי הצורך.

<layout>

ב-Android 7.0 (רמת API 24) ואילך, אלמנט המניפסט <layout> תומך במספר מאפיינים שמשפיעים על האופן שבו פעילות מתנהגת במצב של חלונות מרובים:

  • android:defaultHeight, android:defaultWidth: הגובה והרוחב שמוגדרים כברירת מחדל לפעילות כשהיא מופעלת במצב חלון במחשב.

  • android:gravity: המיקום הראשוני של הפעילות כשהיא מופעלת במצב חלון במחשב. אפשר לעיין בערכים המתאימים בכיתה Gravity.

  • android:minHeight, android:minWidth: הגובה והרוחב המינימליים של הפעילות במצב מסך מפוצל ובמצב חלון במחשב. אם המשתמש מזיז את המפצל במצב מסך מפוצל כדי שהפעילות תהיה קטנה מהגודל המינימלי שצוין, המערכת תגזור את הפעילות לגודל המבוקש על ידי המשתמש.

הקוד הבא מראה איך לציין את המיקום והגודל שמוגדרים כברירת מחדל לפעילות, ואת הגודל המינימלי שלה כשהפעילות מוצגת במצב חלון במחשב:

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end|..."
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

מצב ריבוי חלונות בזמן הריצה

החל מגרסה Android 7.0, המערכת מציעה פונקציונליות שתומכת באפליקציות שאפשר להריץ במצב חלונות מרובים.

תכונות מושבתות במצב ריבוי חלונות

במצב חלונות מרובים, מערכת Android עשויה להשבית או להתעלם מתכונות שלא רלוונטיות לפעילות שמשתפת את מסך המכשיר עם פעילויות או אפליקציות אחרות.

בנוסף, חלק מאפשרויות ההתאמה האישית של ממשק המשתמש של המערכת מושבתות. לדוגמה, אפליקציות לא יכולות להסתיר את שורת הסטטוס אם הן פועלות במצב של כמה חלונות (ראו שליטה בחשיפה של רכיב הממשק של המערכת).

המערכת מתעלמת משינויים במאפיין android:screenOrientation.

שאילתות וקריאות חזרה (callbacks) במצב ריבוי חלונות

בכיתה Activity יש את השיטות הבאות לתמיכה במצב של חלונות מרובים:

  • isInMultiWindowMode(): מציין אם הפעילות מתבצעת במצב של חלונות מרובים.

  • isInPictureInPictureMode(): מציין אם הפעילות מתבצעת במצב 'תמונה בתוך תמונה'.

  • onMultiWindowModeChanged(): המערכת קוראת לשיטה הזו בכל פעם שהפעילות עוברת למצב של חלונות מרובים או יוצאת ממנו. המערכת מעבירה לשיטה את הערך true אם הפעילות נכנסת למצב ריבוי חלונות, או את הערך false אם הפעילות יוצאת ממצב ריבוי חלונות.

  • onPictureInPictureModeChanged(): המערכת קוראת ל-method הזה בכל פעם שהפעילות עוברת למצב 'תמונה בתוך תמונה' או יוצאת ממנו. המערכת מעבירה לשיטה את הערך true אם הפעילות נכנסת למצב 'תמונה בתוך תמונה', או את הערך false אם הפעילות יוצאת ממצב 'תמונה בתוך תמונה'.

בכיתה Fragment מוצגות גרסאות של רבות מהשיטות האלה, למשל Fragment.onMultiWindowModeChanged().

מצב תמונה בתוך תמונה

כדי להעביר פעילות למצב 'תמונה בתוך תמונה', צריך להפעיל את השיטה enterPictureInPictureMode(). השיטה הזו לא משפיעה אם המכשיר לא תומך במצב 'תמונה בתוך תמונה'. מידע נוסף זמין במאמר הוספת סרטונים באמצעות התכונה 'תמונה בתוך תמונה' (PiP).

פעילויות חדשות במצב ריבוי חלונות

כשאתם משיקים פעילות חדשה, אתם יכולים לציין שהפעילות החדשה תוצג לצד הפעילות הנוכחית, אם הדבר אפשרי. משתמשים בדגל הכוונה FLAG_ACTIVITY_LAUNCH_ADJACENT, שמורה למערכת לנסות ליצור את הפעילות החדשה בחלון סמוך, כך ששתי הפעילויות ישתפו את המסך. המערכת עושה כמיטב יכולתה כדי לעשות זאת, אבל לא מובטח שהיא תצליח.

אם המכשיר נמצא במצב חלון במחשב ואתם מריצים פעילות חדשה, תוכלו לציין את המאפיינים של הפעילות החדשה (המיקום במסך והמידות) באמצעות קריאה ל-ActivityOptions.setLaunchBounds(). השיטה לא משפיעה אם המכשיר לא במצב ריבוי חלונות.

ברמת API 30 ומטה, אם מפעילים פעילות בתוך סטאק משימות, הפעילות מחליפה את הפעילות במסך ועוברת בירושה את כל המאפיינים שלה לגבי חלונות מרובים. אם רוצים להפעיל את הפעילות החדשה כחלון נפרד במצב חלונות מרובים, צריך להפעיל אותה בערימה חדשה של משימות.

ב-Android 12 (רמת API ‏31) אפשר לפצל את חלון המשימות של אפליקציה לכמה פעילויות. אתם קובעים איך האפליקציה תציג את הפעילויות שלה – במסך מלא, זו לצד זו או בערימה – על ידי יצירת קובץ תצורה מסוג XML או שליחת קריאות ל-Jetpack WindowManager API.

גרירה ושחרור

המשתמשים יכולים לגרור ולשחרר נתונים מפעילות אחת לפעילות אחרת בזמן ששתי הפעילויות משתפות את המסך. (לפני Android 7.0, המשתמשים יכלו לגרור ולשחרר נתונים רק בפעילות אחת). כדי להוסיף במהירות תמיכה בקבלת תוכן שנמחק, אפשר להיעזר ב-API של DropHelper. במאמר הפעלת גרירה ושחרור מוסבר איך להשתמש בגרירה ושחרור.

כמה מופעים במקביל

לכל פעילות ברמה הבסיסית יש משימה משלה, שמוצגת בחלון משלה. כדי להפעיל מופע חדש של האפליקציה בחלון נפרד, מתחילים פעילויות חדשות עם הדגל FLAG_ACTIVITY_NEW_TASK. אפשר לשלב את ההגדרה הזו עם מאפייני חלונות מרובים כדי לבקש מיקום ספציפי לחלון החדש. לדוגמה, אפליקציית שופינג יכולה להציג כמה חלונות צמודים כדי להשוות בין מוצרים.

בגרסה Android 12 ואילך (רמת API‏ 31 ואילך) אפשר להפעיל שני מופעים של פעילות זה לצד זה באותו חלון משימות בהטמעת פעילות.

אם אתם רוצים לאפשר למשתמשים להפעיל מופע נוסף של האפליקציה ממרכז האפליקציות או מסרגל האפליקציות, צריך להגדיר את הערך android:resizeableActivity="true" במניפסט של הפעילות במרכז האפליקציות ולא להשתמש במצב הפעלה שמונע הפעלה של כמה מופעים. לדוגמה, אפשר ליצור מופע של פעילות singleInstancePerTask כמה פעמים במשימות שונות כשמגדירים את FLAG_ACTIVITY_MULTIPLE_TASK או את FLAG_ACTIVITY_NEW_DOCUMENT.

ב-Android 15 (רמת API 35) ואילך, אפשר להצהיר על תמיכה במספר מכונות באמצעות PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI. הנכס הוא אות מפורש לממשק המשתמש של המערכת כדי לחשוף למשתמש אמצעי בקרה ליצירת כמה מופעים של האפליקציה. הנכס הוא עצמאי ממצב ההפעלה, אבל צריך להשתמש בו רק כשמצב ההפעלה של פעילות או אפליקציה תואם לנכס, למשל כשמצב ההפעלה הוא לא singleInstance.

כשמפעילים כמה מופעים של אפליקציה בחלונות נפרדים במכשיר מתקפל, יכול להיות שמופעים אחד או יותר יישלחו לרקע אם המצב של המכשיר ישתנה. לדוגמה, נניח שהמכשיר פתוח ושני מופעי אפליקציה פועלים בחלונות נפרדים בכל צד של המכשיר. אם המכשיר מקופל, יכול להיות שאחד מהמכונות יושבת במקום לנסות להתאים את החלונות של שתי המכונות למסך קטן יותר.

אימות במצב ריבוי חלונות

גם אם האפליקציה שלכם מטרגטת רמת API 24 ואילך וגם אם לא, כדאי לוודא איך היא מתנהגת במצב של חלונות מרובים, למקרה שמשתמש ינסה להפעיל אותה במצב של חלונות מרובים במכשיר עם Android מגרסה 7.0 ואילך.

בדיקת מכשירים

במכשירים עם Android מגרסה 7.0 (רמת API‏ 24) ואילך יש תמיכה במצב 'חלונות מרובים'.

רמת API ‏23 ומטה

כשמשתמשים מנסים להשתמש באפליקציה במצב ריבוי חלונות, המערכת משנה את גודל האפליקציה באופן גורף, אלא אם האפליקציה מצהירה על כיוון קבוע.

אם האפליקציה לא מצהירה על כיוון קבוע, צריך להפעיל אותה במכשיר עם Android מגרסה 7.0 ואילך ולנסות להעביר אותה למצב מסך מפוצל. מוודאים שחוויית המשתמש טובה גם כשמשנים את גודל האפליקציה באופן ידני.

אם האפליקציה מצהירה על כיוון מוצמד, צריך לנסות להעביר אותה למצב חלונות מרובים. מוודאים שהאפליקציה נשארת במצב מסך מלא.

רמות API 24 עד 30

אם האפליקציה שלכם מטרגטת לרמות API 24 עד 30 ולא משביתה את התמיכה בכמה חלונות, עליכם לוודא שההתנהגות הבאה מתרחשת גם במצב מסך מפוצל וגם במצב חלון במחשב:

  • פותחים את האפליקציה במסך מלא, ואז לוחצים לחיצה ארוכה על הלחצן סמל הפריטים האחרונים כדי לעבור למצב חלונות מרובים. מוודאים שהאפליקציה עוברת בצורה תקינה.

  • מריצים את האפליקציה ישירות במצב ריבוי חלונות ומוודאים שהיא מופעלת כראוי. כדי להפעיל אפליקציה במצב ריבוי חלונות, לוחצים על הלחצן מהזמן האחרון, לוחצים לחיצה ארוכה על סרגל הכותרת של האפליקציה וגוררים אותו לאחד מהאזורים המודגשים במסך.

  • כדי לשנות את הגודל של האפליקציה במצב מסך מפוצל, גוררים את המחיצה במסך. מוודאים שהאפליקציה משתנה לגודל הרצוי בלי לקרוס, ושאלמנטים חיוניים בממשק המשתמש גלויים.

  • אם ציינת מידות מינימום לאפליקציה, נסו לשנות את גודל האפליקציה כך שגודל החלון שלה יהיה קטן יותר מהמידות האלה. מוודאים שלא ניתן לשנות את הגודל של האפליקציה כך שיהיה קטן מהמידות המינימליות שצוינו.

  • לאורך כל הבדיקות, מוודאים שהביצועים של האפליקציה תקינים. לדוגמה, מוודאים שאין עיכוב ארוך מדי עד לעדכון ממשק המשתמש אחרי שינוי הגודל של האפליקציה.

רמת API 31 ואילך

אם האפליקציה שלכם מטרגטת לרמת API 31 ואילך, והרוחב והגובה המינימליים של הפעילות הראשית קטנים או שווים למימדים המתאימים של אזור התצוגה הזמין, עליכם לוודא את כל ההתנהגויות שמפורטות לגבי רמות API 24 עד 30.

רשימת משימות לבדיקה

כדי לבדוק את ביצועי האפליקציה במצב 'חלונות מרובים', כדאי לנסות את הפעולות הבאות. כדאי לנסות את הפעולות האלה גם במסך מפוצל וגם במצב חלון במחשב, אלא אם צוין אחרת.

  • מעבר למצב ריבוי חלונות ויציאה ממנו.

  • עוברים מהאפליקציה שלכם לאפליקציה אחרת, ומוודאים שהאפליקציה פועלת כראוי כשהיא גלויה אבל לא פעילה. לדוגמה, אם באפליקציה שלכם מופעל סרטון, עליכם לוודא שהסרטון ממשיך לפעול בזמן שהמשתמש מבצע פעולות באפליקציה אחרת.

  • במצב מסך מפוצל, אפשר לנסות להזיז את המפצל של המסך כדי להגדיל או להקטין את האפליקציה. כדאי לנסות את הפעולות האלה גם בצד לצד וגם אחת מעל השנייה בהגדרות. מוודאים שהאפליקציה לא קורסת, שהפונקציונליות החיונית גלויה ושפעולת שינוי הגודל לא נמשכת יותר מדי זמן.

  • ביצוע כמה פעולות שינוי גודל ברצף מהיר. מוודאים שהאפליקציה לא קורסת או דולפת זיכרון. כלי הניתוח של הזיכרון ב-Android Studio מספק מידע על השימוש של האפליקציה בזיכרון (מידע נוסף זמין במאמר בדיקת השימוש של האפליקציה בזיכרון באמצעות כלי הניתוח של הזיכרון).

  • משתמשים באפליקציה באופן רגיל במספר הגדרות חלון שונות, ומוודאים שהיא פועלת כראוי. מוודאים שהטקסט קריא ושהרכיבים בממשק המשתמש לא קטנים מדי ולא ניתן לבצע איתם אינטראקציה.

התמיכה בריבוי חלונות מושבתת

ברמות API 24 עד 30, אם השבתתם את התמיכה בכמה חלונות על ידי הגדרת android:resizeableActivity="false", עליכם להפעיל את האפליקציה במכשיר עם Android מגרסה 7.0 עד 11 ולנסות להעביר את האפליקציה למצב מסך מפוצל ולמצב חלון במחשב. מוודאים שהאפליקציה נשארת במצב מסך מלא.

מקורות מידע נוספים

מידע נוסף על תמיכה בריבוי חלונות ב-Android זמין במאמרים הבאים:

מומלץ לך * הערה: טקסט הקישור מוצג כש-JavaScript מושבת * מצב תאימות למכשיר * תמיכה בשינוי הגודל של מסך גדול * טיפול בשינויים בהגדרות