הצגת התוכן מקצה לקצה באפליקציה

כדאי לנסות את התכונה 'כתיבה מהירה'
Jetpack Compose היא ערכת הכלים המומלצת לבניית ממשק משתמש ב-Android. איך עובדים במצב 'מלא' בחלונית הכתיבה?

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

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

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

איור 1. עמודות מערכת בפריסה מקצה לקצה.

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

  1. הפעלת תצוגה מקצה לקצה
  2. לטפל בחפיפות חזותיות.
  3. כדאי להציג מודעות גרפיות מאחורי סרגלי המידע של המערכת.
דוגמה לתמונה שמופיעה מאחורי שורת הסטטוס
איור 2. דוגמה לתמונה שמופיעה מאחורי שורת הסטטוס.

הפעלת תצוגה מקצה לקצה

אם האפליקציה שלכם מטרגטת ל-SDK 35 ואילך, התצוגה מקצה לקצה מופעלת באופן אוטומטי במכשירי Android 15 ואילך.

כדי להפעיל מקצה לקצה בגרסאות Android קודמות, צריך לבצע את הפעולות הבאות:

  1. מוסיפים תלות לספרייה androidx.activity בקובץ build.gradle של האפליקציה או המודול:

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }

    Groovy

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
  2. מייבאים את פונקציית התוסף enableEdgeToEdge לאפליקציה:

כדי להפעיל את התצוגה מקצה לקצה באופן ידני, מקישים על enableEdgeToEdge ב-onCreate של Activity. צריך לקרוא לה לפני setContentView.

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

Java

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

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

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

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

טיפול בחפיפה באמצעות קטעי תמונה

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

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

סוגי הפריימים שמתאימים להצגת האפליקציה מקצה לקצה הם:

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

  • Display cutout insets (הצגת קטעי תמונה שמותאמים למגרעת במסך): לאזורים שבהם עשויה להיות מגרעת במסך בגלל צורת המכשיר.

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

רכיבי מידע בתוך סרגל המידע

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

לדוגמה, לחצן הפעולה הצף (FAB) שמופיע בתמונה מספר 3 מוסתר חלקית על ידי סרגל הניווט:

דוגמה להטמעה מקצה לקצה, אבל סרגל הניווט מכסה את הלחצן המהיר
איור 3. סרגל הניווט חופף ללחצן ה-FAB בפריסה מקצה לקצה.

כדי למנוע חפיפה חזותית כזו במצב תנועות או במצב לחצנים, אפשר להגדיל את השוליים של התצוגה באמצעות getInsets(int) עם WindowInsetsCompat.Type.systemBars().

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

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left,
      bottomMargin = insets.bottom,
      rightMargin = insets.right,
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

אם מחילים את הפתרון הזה על הדוגמה שמוצגת באיור 3, אין חפיפה חזותית במצב הלחצן, כפי שמוצג באיור 4:

סרגל ניווט שקוף שלא מכסה את לחצן ה-FAB
איור 4. פתרון חפיפה ויזואלית במצב לחצן.

אותו הדבר חל על מצב ניווט באמצעות תנועות, כפי שמוצג באיור 5:

מסך מקצה לקצה עם ניווט באמצעות תנועות
איור 5. פתרון חפיפה חזותית במצב ניווט באמצעות תנועות.

הצגת קטעי תמונה עם מגרעת במסך

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

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

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

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

מגדירים את clipToPadding כ-RecyclerView כדי שהרווח יגולול עם פריטי הרשימה. כך הפריטים יכולים להופיע מאחורי סרגלי המערכת כשהמשתמש גולל, כמו בדוגמה הבאה.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

תנועות מובנות במערכת

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

דוגמה לשילוב של תנועות במערכת
איור 6. insets של תנועות במערכת.

בדומה לרכיבים הפנימיים של שורת המערכת, אפשר למנוע חפיפה בין הרכיבים הפנימיים של תנועות המערכת באמצעות getInsets(int) עם WindowInsetsCompat.Type.systemGestures().

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

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

דוגמה למדידות של תנועה מובנית במערכת
איור 7. מדידות של תנועות מובנות במערכת.

בדוגמת הקוד הבאה מוסבר איך מטמיעים רכיבי 'הכנסה של תנועות מערכת':

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Material Components

רכיבי Android Materials רבים מבוססי תצוגות (com.google.android.material){:.external} מטפלים באופן אוטומטי ברכיבי inset, כולל BottomAppBar, BottomNavigationView, NavigationRailView ו-NavigationView

עם זאת, AppBarLayout לא מטפל באופן אוטומטי בהטמעות. מוסיפים את הערך android:fitsSystemWindows="true" כדי לטפל בפריטים מוטמעים בחלק העליון.

איך מטפלים ברכיבים מוכנסים באמצעות Material Components ב-Compose

מצב אימרסיבי

יש תוכן שהכי כדאי לצפות בו במסך מלא, כדי לספק למשתמש חוויה מעט יותר immersive. אפשר להסתיר את שורת הסטטוס ואת שורת הסטטוס העליונה במצב צפייה immersive באמצעות הספריות WindowInsetsController ו-WindowInsetsControllerCompat:

Kotlin

val windowInsetsController =
      WindowCompat.getInsetsController(window, window.decorView)

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

Java

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

למידע נוסף על הטמעת התכונה הזו, עיינו במאמר הסתרת פסי המערכת של מצב עשיר.

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

בחומרי העזר הבאים תוכלו למצוא מידע נוסף על WindowInsets, ניווט באמצעות תנועות ועל אופן הפעולה של ערכות הרכב: