Перенос координатораLayout в Compose

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

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

  • Компоненты и макеты Material : документация по компонентам Material Design, которые поддерживаются в Compose, например Scaffold .
  • Миграция Sunflower на Jetpack Compose : запись в блоге, в которой описывается процесс миграции с Views на Compose примера приложения Sunflower, содержащего CoordinatorLayout .
{% дословно %} {% endverbatim %} {% дословно %} {% endverbatim %}