העברת CoordinatorLayout לכתיבה

‫CoordinatorLayout הוא ViewGroup שמאפשר פריסות מורכבות, חופפות ומשולבות. הוא משמש כמאגר שמאפשר אינטראקציות ספציפיות של Material Design, כמו הרחבה או כיווץ של סרגלי כלים וגיליונות תחתונים, לתצוגות (Views) שכלולות בו.

ב-Compose, המקבילה הכי קרובה ל-CoordinatorLayout היא Scaffold. Scaffold מספק משבצות תוכן לשילוב רכיבי Material בדפוסי מסך ובאינטראקציות נפוצים. בדף הזה מוסבר איך להעביר את ההטמעה של CoordinatorLayout לשימוש ב-Scaffold ב-Compose.

שלבי ההעברה

כדי להעביר את CoordinatorLayout אל Scaffold, פועלים לפי השלבים הבאים:

  1. בקטע הקוד הבא, CoordinatorLayout מכיל AppBarLayout שמכיל ToolBar, ViewPager ו-FloatingActionButton. מסמנים כהערה את CoordinatorLayout ואת הצאצאים שלו מההיררכיה של ממשק המשתמש, ומוסיפים ComposeView כדי להחליף אותו.

    ```xml

    <!-- AppBarLayout contents here -->
    

    ```

  2. ב-Fragment או ב-Activity, מקבלים הפניה ל-ComposeView שהוספתם וקוראים ל-method‏ setContent. בגוף השיטה, מגדירים Scaffold כתוכן שלה:

    composeView.setContent {
        Scaffold(Modifier.fillMaxSize()) { contentPadding ->
            // Scaffold contents
            // ...
        }
    }

  3. בתוכן של Scaffold, מוסיפים את התוכן הראשי של המסך. מכיוון שהתוכן הראשי ב-XML שלמעלה הוא ViewPager2, נשתמש ב-HorizontalPager, שהוא המקבילה שלו ב-Compose. ה-lambda של content ב-Scaffold מקבלת גם מופע של PaddingValues שצריך להחיל על שורש התוכן. אפשר להשתמש ב-Modifier.padding כדי להחיל את אותה PaddingValues על HorizontalPager.

    composeView.setContent {
        Scaffold(Modifier.fillMaxSize()) { contentPadding ->
            val pagerState = rememberPagerState {
                10
            }
            HorizontalPager(
                state = pagerState,
                modifier = Modifier.padding(contentPadding)
            ) { /* Page contents */ }
        }
    }

  4. אפשר להשתמש במשבצות תוכן אחרות ש-Scaffold מספק כדי להוסיף עוד רכיבי מסך ולהעביר את תצוגות הצאצא שנותרו. אפשר להשתמש במשבצת topBar כדי להוסיף TopAppBar, ובמשבצת floatingActionButton כדי להוסיף FloatingActionButton.

    composeView.setContent {
        Scaffold(
            Modifier.fillMaxSize(),
            topBar = {
                TopAppBar(
                    title = {
                        Text("My App")
                    }
                )
            },
            floatingActionButton = {
                FloatingActionButton(
                    onClick = { /* Handle click */ }
                ) {
                    Icon(
                        Icons.Filled.Add,
                        contentDescription = "Add Button"
                    )
                }
            }
        ) { contentPadding ->
            val pagerState = rememberPagerState {
                10
            }
            HorizontalPager(
                state = pagerState,
                modifier = Modifier.padding(contentPadding)
            ) { /* Page contents */ }
        }
    }

תרחישים נפוצים לדוגמה

כיווץ והרחבה של סרגלי כלים

במערכת View, כדי לכווץ ולהרחיב את סרגל הכלים באמצעות CoordinatorLayout, משתמשים ב-AppBarLayout כמאגר לסרגל הכלים. לאחר מכן, אפשר לציין Behavior עד layout_behavior ב-XML בתצוגה הניתנת לגלילה המשויכת (כמו RecyclerView או NestedScrollView) כדי להצהיר איך סרגל הכלים מתכווץ או מתרחב בזמן הגלילה.

ב-Compose, אפשר להשיג אפקט דומה באמצעות TopAppBarScrollBehavior. לדוגמה, כדי להטמיע סרגל כלים מתכווץ/מתרחב שמופיע כשגוללים למעלה, פועלים לפי השלבים הבאים:

  1. מפעילים את TopAppBarDefaults.enterAlwaysScrollBehavior() כדי ליצור TopAppBarScrollBehavior.
  2. מספקים את ה-TopAppBarScrollBehavior שנוצר ל-TopAppBar.
  3. מחברים את NestedScrollConnection באמצעות Modifier.nestedScroll ב-Scaffold כדי שה-Scaffold יוכל לקבל אירועי גלילה בתצוגות עץ כשהתוכן שניתן לגלילה נגלל למעלה או למטה. כך, סרגל האפליקציה הכלול יכול להתכווץ או להתרחב בהתאם לגלילה בתוכן.

    // 1. Create the TopAppBarScrollBehavior
    val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
    
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text("My App")
                },
                // 2. Provide scrollBehavior to TopAppBar
                scrollBehavior = scrollBehavior
            )
        },
        // 3. Connect the scrollBehavior.nestedScrollConnection to the Scaffold
        modifier = Modifier
            .fillMaxSize()
            .nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { contentPadding ->
        /* Contents */
        // ...
    }

התאמה אישית של אפקט הגלילה של כיווץ/הרחבה

אפשר להגדיר כמה פרמטרים ל-enterAlwaysScrollBehavior כדי להתאים אישית את אפקט האנימציה של הכיווץ וההרחבה. ב-TopAppBarDefaults יש גם TopAppBarScrollBehavior אחרים, כמו exitUntilCollapsedScrollBehavior, שמרחיב את סרגל האפליקציה רק כשגוללים את התוכן עד למטה.

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

מגירות

ב-Views, מטמיעים חלונית הזזה לניווט באמצעות DrawerLayout בתור התצוגה ברמה הבסיסית (root). בתורו, CoordinatorLayout הוא תצוגת צאצא של DrawerLayout. ה-DrawerLayout מכיל גם תצוגת צאצא נוספת, כמו NavigationView, כדי להציג את אפשרויות הניווט בתפריט ההזזה.

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

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    Scaffold(Modifier.fillMaxSize()) { contentPadding ->
        // Scaffold content
        // ...
    }
}

מידע נוסף זמין במאמר בנושא מגירות.

סרגלים אינטראקטיביים

ל-Scaffold יש משבצת snackbarHost, שיכולה לקבל רכיב SnackbarHost שניתן לשילוב כדי להציג Snackbar.

val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
    snackbarHost = {
        SnackbarHost(hostState = snackbarHostState)
    },
    floatingActionButton = {
        ExtendedFloatingActionButton(
            text = { Text("Show snackbar") },
            icon = { Icon(Icons.Filled.Image, contentDescription = "") },
            onClick = {
                scope.launch {
                    snackbarHostState.showSnackbar("Snackbar")
                }
            }
        )
    }
) { contentPadding ->
    // Screen content
    // ...
}

מידע נוסף זמין במאמר בנושא הודעות קופצות.

מידע נוסף

למידע נוסף על העברת CoordinatorLayout לפיתוח נייטיב, אפשר לעיין במקורות המידע הבאים: