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

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

במצב 'כתיבה', המקבילה הקרובה ביותר ל-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. בגוף ה-method, להגדיר את 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 */ }
        }
    }

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

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

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

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

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

    // 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 לדוגמה.

מגירות

בקטע 'תצוגות', אפשר ליישם חלונית הזזה לניווט באמצעות 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, תוכלו לעיין במקורות המידע הבאים: