Как перенести 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. В своем фрагменте или объекте 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.

Ящики

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