Как перенести CoordinatorLayout в Compose

CoordinatorLayout – это ViewGroup, который позволяет создавать сложные, перекрывающиеся и вложенные макеты. Он используется как контейнер, позволяющий включать определенные взаимодействия Material Design, такие как разворачивание и сворачивание панелей инструментов и нижних экранов, для содержащихся в нем представлений.

В 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 и вызовите для него метод 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, чтобы добавить больше элементов экрана и перенести оставшиеся дочерние представления. Слот 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.

Ящики

При использовании представлений вы реализуете панель навигации, используя DrawerLayout в качестве корневого представления. В свою очередь, CoordinatorLayout – это дочернее представление для DrawerLayout. DrawerLayout также содержит другой дочерний элемент, например NavigationView, для отображения параметров навигации на панели.

В Compose панель навигации можно реализовать с помощью composable-функции 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, который может принимать composable-функцию 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 можно найти в следующих ресурсах: