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

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

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

שלבי ההעברה

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

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

    <!--  <androidx.coordinatorlayout.widget.CoordinatorLayout-->
    <!--      android:id="@+id/coordinator_layout"-->
    <!--      android:layout_width="match_parent"-->
    <!--      android:layout_height="match_parent"-->
    <!--      android:fitsSystemWindows="true">-->
    
    <!--    <androidx.compose.ui.platform.ComposeView-->
    <!--        android:id="@+id/compose_view"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="match_parent"-->
    <!--        app:layout_behavior="@string/appbar_scrolling_view_behavior" />-->
    
    <!--    <com.google.android.material.appbar.AppBarLayout-->
    <!--        android:id="@+id/app_bar_layout"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="wrap_content"-->
    <!--        android:fitsSystemWindows="true"-->
    <!--        android:theme="@style/Theme.Sunflower.AppBarOverlay">-->
    
        <!-- AppBarLayout contents here -->
    
    <!--    </com.google.android.material.appbar.AppBarLayout>-->
    
    <!--  </androidx.coordinatorlayout.widget.CoordinatorLayout>-->
    
    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/compose_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
  2. ב-Fragment או ב-Activity, מקבלים הפניה ל-ComposeView שהוספתם זה עתה ומפעילים עליו את השיטה setContent. בגוף השיטה, מגדירים Scaffold כתוכן שלה:

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

  3. בתוכן של Scaffold, מוסיפים את התוכן הראשי של המסך. מכיוון שהתוכן הראשי ב-XML שלמעלה הוא ViewPager2, נשתמש ב-HorizontalPager, שהוא המקבילה שלו ב-Compose. פונקציית הלמהדה 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 מספק כדי להוסיף עוד רכיבי מסך ולהעביר את שאר תצוגות הצאצאים. אפשר להשתמש ב-slot‏ topBar כדי להוסיף TopAppBar, וב-slot‏ 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 */ }
        }
    }

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

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

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

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

  1. כדי ליצור TopAppBarScrollBehavior, צריך להתקשר למספר TopAppBarDefaults.enterAlwaysScrollBehavior().
  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 בתור תצוגת הבסיס. בתורו, ה-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 ל-Compose, תוכלו לעיין במקורות המידע הבאים: