Jetpack Compose 使设计和构建应用 UI 变得更加容易。Compose 通过以下方式将状态转换为 UI 元素:
- 元素的组合
- 元素的布局
- 元素的绘制
本文档重点介绍元素的布局,解释了 Compose 提供的一些构建块,以帮助您布局 UI 元素。
Compose 中布局的目标
Jetpack Compose 布局系统的实现有两个主要目标:
可组合函数基础知识
可组合函数是 Compose 的基本构建块。可组合函数是一个发出 Unit
的函数,用于描述 UI 的某个部分。该函数接受一些输入并生成屏幕上显示的内容。有关可组合项的更多信息,请参阅Compose 心智模型文档。
可组合函数可能会发出多个 UI 元素。但是,如果您不提供关于如何排列它们的指导,Compose 可能会以您不喜欢的方式排列这些元素。例如,此代码生成两个文本元素:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
如果没有关于您希望如何排列它们的指导,Compose 会将文本元素堆叠在一起,导致它们无法阅读。
Compose 提供了一系列即用型布局,可帮助您排列 UI 元素,并使您可以轻松定义自己的更专业的布局。
标准布局组件
在许多情况下,您只需使用Compose 的标准布局元素即可。
使用Column
在屏幕上垂直放置项目。
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
同样,使用Row
在屏幕上水平放置项目。Column
和 Row
都支持配置其所包含元素的对齐方式。
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
使用Box
将元素叠加在一起。Box
还支持配置其所包含元素的特定对齐方式。
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
通常,这些构建块就是您所需要的一切。您可以编写自己的可组合函数,将这些布局组合成更适合您的应用的复杂布局。
要设置 Row
中子项的位置,请设置 horizontalArrangement
和 verticalAlignment
参数。对于 Column
,请设置 verticalArrangement
和 horizontalAlignment
参数。
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
布局模型
在布局模型中,UI 树是在单次遍历中布局的。首先要求每个节点测量自身,然后递归测量所有子节点,将大小约束沿树向下传递给子节点。然后,对叶节点进行大小调整和放置,并将解析的大小和放置指令沿树向上传递。
简而言之,父级在子级之前测量,但在子级之后进行大小调整和放置。
考虑以下 SearchResult
函数。
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
此函数产生以下 UI 树。
SearchResult
Row
Image
Column
Text
Text
在 SearchResult
示例中,UI 树布局遵循以下顺序:
- 根节点
Row
被要求测量。 - 根节点
Row
要求其第一个子节点Image
进行测量。 Image
是一个叶节点(即它没有子节点),因此它报告一个大小并返回放置指令。- 根节点
Row
要求其第二个子节点Column
进行测量。 Column
节点要求其第一个Text
子节点进行测量。- 第一个
Text
节点是一个叶节点,因此它报告一个大小并返回放置指令。 Column
节点要求其第二个Text
子节点进行测量。- 第二个
Text
节点是一个叶节点,因此它报告一个大小并返回放置指令。 - 现在,
Column
节点已经测量、调整大小并放置了其子节点,它可以确定自己的大小和放置。 - 现在,根节点
Row
已经测量、调整大小并放置了其子节点,它可以确定自己的大小和放置。
性能
Compose 通过只测量子节点一次来实现高性能。单次测量有利于性能,使 Compose 能够高效处理深层 UI 树。如果一个元素测量其子节点两次,而该子节点又测量其每个子节点两次,依此类推,那么一次完整的 UI 布局尝试将不得不做大量工作,从而难以保持您的应用高性能。
如果您的布局由于某种原因需要多次测量,Compose 提供了一个特殊系统——固有测量。您可以在Compose 布局中的固有测量中阅读有关此功能的更多信息。
由于测量和放置是布局过程中的不同子阶段,因此任何只影响项目放置而不影响测量的更改都可以单独执行。
在布局中使用修饰符
如Compose 修饰符中所述,您可以使用修饰符来装饰或增强您的可组合项。修饰符对于自定义布局至关重要。例如,这里我们链式调用多个修饰符来自定义 ArtistCard
:
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
在上面的代码中,请注意同时使用了不同的修饰符函数。
clickable
使可组合项响应用户输入并显示涟漪效果。padding
在元素周围放置空间。fillMaxWidth
使可组合项填充其父级赋予的最大宽度。size()
指定元素的首选宽度和高度。
可滚动布局
在Compose 手势文档中了解有关可滚动布局的更多信息。
对于列表和懒惰列表,请查看Compose 列表文档。
响应式布局
布局设计时应考虑不同的屏幕方向和外形规格大小。Compose 开箱即用地提供了一些机制,以方便您的可组合布局适应各种屏幕配置。
约束
为了了解来自父级的约束并相应地设计布局,您可以使用 BoxWithConstraints
。测量约束可以在内容 lambda 的作用域中找到。您可以使用这些测量约束为不同的屏幕配置组合不同的布局。
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
基于槽位的布局
Compose 提供了基于 Material Design 的各种可组合项,并包含 androidx.compose.material:material
依赖项(在 Android Studio 中创建 Compose 项目时已包含),使 UI 构建变得容易。Drawer
、FloatingActionButton
和 TopAppBar
等元素均已提供。
Material 组件大量使用了槽位 API,这是 Compose 引入的一种模式,可在可组合项之上添加一层自定义功能。这种方法使组件更加灵活,因为它们接受一个可以自行配置的子元素,而无需公开子元素的所有配置参数。槽位在 UI 中留出空白区域,供开发者随意填充。例如,这些是您可以在 TopAppBar
中自定义的槽位:
可组合项通常接受一个 content
可组合 lambda ( content: @Composable () -> Unit
)。槽位 API 暴露了多个 content
参数以供特定用途。例如,TopAppBar
允许您为 title
、navigationIcon
和 actions
提供内容。
例如,Scaffold
允许您使用基本的 Material Design 布局结构实现 UI。Scaffold
为最常见的顶级 Material 组件提供了槽位,例如 TopAppBar
、BottomAppBar
、FloatingActionButton
和 Drawer
。通过使用 Scaffold
,可以轻松确保这些组件正确定位并协同工作。
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本
- Compose 修饰符
- 适用于 Jetpack Compose 的 Kotlin
- Material 组件和布局