Jetpack Compose 可让您更轻松地设计和构建应用的界面。Compose 通过以下方法将状态转换为界面元素:
- 元素的组合
- 元素的布局
- 元素的绘图
本文重点介绍了元素的布局,说明 Compose 为协助构建界面元素而提供的一些构建块。
Compose 中布局的目标
布局系统的 Jetpack Compose 实现有两个主要目标:
可组合函数的基础知识
可组合函数是 Compose 的基本构建块。可组合函数是一种发出 Unit
的函数,用于描述界面中的某一部分。该函数接受一些输入并生成屏幕上显示的内容。如需详细了解可组合项,请参阅 Compose 构思模型文档。
一个可组合函数可能会发出多个界面元素。不过,如果您未提供有关如何排列这些元素的指导,Compose 可能会以您不喜欢的方式排列它们。例如,以下代码会生成两个文本元素:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
如果您未提供有关如何排列这两个文本元素的指导,Compose 会将它们堆叠在一起,使其无法阅读:
Compose 提供了一系列现成可用的布局来帮助您排列界面元素,并可让您轻松定义自己的更专业布局。
标准布局组件
在许多情况下,您只需使用 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 { /*...*/ } } }
布局模型
在布局模型中,通过单次传递即可完成界面树布局。首先,系统会要求每个节点对自身进行测量,然后以递归方式完成所有子节点的测量,并将尺寸约束条件沿着树向下传递给子节点。再后,确定叶节点的尺寸和放置位置,并将经过解析的尺寸和放置指令沿着树向上回传。
简而言之,父节点会在其子节点之前进行测量,但会在其子节点的尺寸和放置位置确定之后再对自身进行调整。
请参考以下 SearchResult
函数。
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
此函数会生成以下界面树。
SearchResult
Row
Image
Column
Text
Text
在 SearchResult
示例中,界面树布局遵循以下顺序:
- 系统要求根节点
Row
对自身进行测量。 - 根节点
Row
要求其第一个子节点(即Image
)进行测量。 Image
是一个叶节点(也就是说,它没有子节点),因此该节点会报告尺寸并返回放置指令。- 根节点
Row
要求其第二个子节点(即Column
)进行测量。 - 节点
Column
要求其第一个子节点Text
进行测量。 - 由于第一个节点
Text
是叶节点,因此该节点会报告尺寸并返回放置指令。 - 节点
Column
要求其第二个子节点Text
进行测量。 - 由于第二个节点
Text
是叶节点,因此该节点会报告尺寸并返回放置指令。 - 现在,节点
Column
已测量其子节点,并已确定其子节点的尺寸和放置位置,接下来它可以确定自己的尺寸和放置位置了。 - 现在,根节点
Row
已测量其子节点,并已确定其子节点的尺寸和放置位置,接下来它可以确定自己的尺寸和放置位置了。
性能
Compose 通过只测量一次子项来实现高性能。单遍测量对性能有利,使 Compose 能够高效地处理较深的界面树。如果某个元素测量了它的子元素两次,而该子元素又测量了它的子元素两次,依此类推,那么一次尝试布置整个界面就不得不做大量的工作,这将很难让应用保持良好的性能。
如果布局由于某种原因需要多次测量,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 项目时提供),旨在简化界面的构建。诸如 Drawer
、FloatingActionButton
和 TopAppBar
之类的元素都有提供。
Material 组件大量使用槽位 API,这是 Compose 引入的一种模式,它在可组合项之上带来一层自定义设置。这种方法使组件变得更加灵活,因为它们接受可以自行配置的子元素,而不必公开子元素的每个配置参数。槽位会在界面中留出空白区域,让开发者按照自己的意愿来填充。例如,下面是您可以在 TopAppBar
中自定义的槽位:
可组合项通常采用 content
可组合 lambda (content: @Composable
() -> Unit
)。槽位 API 会针对特定用途公开多个 content
参数。例如,TopAppBar
可让您为 title
、navigationIcon
和 actions
提供内容。
例如,Scaffold
可让您实现具有基本 Material Design 布局结构的界面。Scaffold
可以为最常见的顶级 Material 组件(如 TopAppBar
、BottomAppBar
、FloatingActionButton
和 Drawer
)提供槽位。通过使用 Scaffold
,可轻松确保这些组件得到适当放置且正确地协同工作。
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- Compose 修饰符
- Kotlin 对 Jetpack Compose 的支持
- Material 组件和布局