בניית פריסה של רשימה ופירוט

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

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

הטמעת תבנית של ממשק משתמש באמצעות ListDetailPaneScaffold

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

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

הצהרת יחסי תלות

ListDetailPaneScaffold הוא חלק מספריית הפריסות המותאמות של Material 3.

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

Kotlin

implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")

Groovy

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • אדפטיביות – אבני בניין ברמה נמוכה, כמו HingeInfo ו-Posture
  • adaptive-layout – פריסות מותאמות כמו ListDetailPaneScaffold ו-SupportingPaneScaffold
  • adaptive-navigation – רכיבים מורכבים לניווט בתוך חלוניות ובין חלוניות

שימוש בסיסי

מטמיעים את ListDetailPaneScaffold באופן הבא:

  1. משתמשים בכיתה שמייצגת את התוכן שנבחר. הסוג צריך להיות Parcelable כדי לתמוך בשמירה ובשחזור של פריט הרשימה שנבחר. אפשר להשתמש בפלאגין kotlin-parcelize כדי ליצור את הקוד בשבילכם.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. יוצרים ThreePaneScaffoldNavigator באמצעות rememberListDetailPaneScaffoldNavigator ומוסיפים BackHandler. בעזרת הניווט הזה אפשר לעבור בין הרשימה, חלונית הפרטים והחלוניות הנוספות. ההצהרה על סוג כללי מאפשרת לנווט לעקוב גם אחרי מצב התבנית (כלומר, איזה MyItem מוצג). מכיוון שהסוג הזה מתחלק למקטעים, הניווט יכול לשמור ולשחזר את המצב כדי לטפל באופן אוטומטי בשינויים בהגדרות. BackHandler תומך בניווט אחורה באמצעות תנועת החזרה או הלחצן של המערכת. ההתנהגות הצפויה של לחצן החזרה לאחור ב-ListDetailPaneScaffold תלויה בגודל החלון ובערך הנוכחי של התשתית. אם ה-ListDetailPaneScaffold יכול לתמוך בחזרה למצב הנוכחי, הערך של canNavigateBack() הוא true, וה-BackHandler מופעל.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. מעבירים את scaffoldState מ-navigator ל-ListDetailPaneScaffold הניתן ליצירה.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. מספקים את ההטמעה של חלונית הרשימות ל-ListDetailPaneScaffold. כדי להחיל את אנימציות ברירת המחדל של החלוניות במהלך הניווט, משתמשים ב-AnimatedPane. לאחר מכן, משתמשים ב-ThreePaneScaffoldNavigator כדי לנווט לחלונית הפרטים, ListDetailPaneScaffoldRole.Detail, ולהציג את הפריט שהוענק.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. כוללים את ההטמעה של חלונית הפרטים ב-ListDetailPaneScaffold. בסיום הניווט, השדה currentDestination מכיל את החלונית שהאפליקציה עברה אליה, כולל התוכן שמוצג בחלונית. המאפיין content הוא מאותו סוג שצוין בקריאה המקורית ל-remember (MyItem בדוגמה הזו), כך שתוכלו לגשת למאפיין גם כדי לקבל נתונים שצריך להציג.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

אחרי שתטמיעו את השלבים שלמעלה, הקוד שלכם אמור להיראות כך:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)