一、布局
官网对于Compose
布局的描述
可组合函数是 Compose 的基本构建块。可组合函数是一种发出
Unit
的函数,用于描述界面中的某一部分。该函数接受一些输入并生成屏幕上显示的内容。如需详细了解可组合项,请参阅 Compose 构思模型文档。
一个可组合函数可能会发出多个界面元素。不过,如果您未提供有关如何排列这些元素的指导,Compose 可能会以您不喜欢的方式排列它们。
当我们尝试着像如下编写代码时
@Composable
fun MainPage() {
Text(text = "Hello,Jetpack Compose!")
Text(text = "hello,jetpack compose!")
}
在预览视图中会发现两个Text
重叠了
在xml中,我们可以用各种布局方式来排列/约束视图元素的位置,那么在Compose
中如何实现呢?Compose
中有没有类似于LinearLayout
、FrameLaoyout
、ConstraintLayout
的东西呢?
答案是:必然有。
在许多情况下,您只需使用 Compose 的标准布局元素即可。
通过以下几种布局方式,基本可以满足日常的开发布局需求。
1. Row
Row
可以理解为Xml布局中LinearLayout
的horizontal
模式,例如:
@Composable
fun MainPage() {
Row(){
Text(text = "Hello")
Text(text = ",")
Text(text = "jetpack compose!")
}
}
通过Row
的源码可以看到我们还可以传递如下几个参数:
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) {
...
}
参数 | 类型 | 默认值 | 含义 |
---|---|---|---|
modifier | Modifier | Modifier | 布局的修饰符 |
horizontalArrangement | Arrangement.Horizontal | Arrangement.Start | 布局子级的 水平 放置方式,默认从布局开始往布局结束方向放置 |
verticalAlignment | Alignment.Vertical | Alignment.Top | 布局子级的 垂直 对其方式,默认从布局顶部对齐 |
例如:
需要注意的是,和LinearLayout一样,超出布局设置的最大宽度或高度的视图将不可见
2. Column
Column
可以理解为Xml布局中LinearLayout
的vertical
模式,例如:
@Composable
fun MainPage() {
Column(Modifier.padding(Dp(50f))) {
Text(text = "Hello")
Text(text = ",")
Text(text = "jetpack compose!")
}
}
通过Column
的源码可以看到我们还可以传递如下几个参数:
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {
...
}
参数 | 类型 | 默认值 | 含义 |
---|---|---|---|
modifier | Modifier | Modifier | 布局的修饰符 |
verticalArrangement | Arrangement.Vertical | Arrangement.Top | 布局子级的 竖直 放置方式,默认从布局顶部往布局底部方向放置 |
horizontalAlignment | Alignment.Horizontal | Alignment.Start | 布局子级的 水平 对其方式,默认从布局开始对齐 |
Column有和Row同样的问题,注意用于修饰Column子级放置和对其方式和Row的参数是不一样的
3. Box
Box
可以理解为Xml布局中FrameLayout
,例如:
@Composable
fun MainPage() {
Box(Modifier.size(Dp(300f), Dp(150f)),
contentAlignment = Alignment.Center) {
Box(modifier = Modifier
.background(MaterialTheme.colors.error)
.size(Dp(200f), Dp(100f)))
Box(modifier = Modifier
.background(MaterialTheme.colors.secondary)
.size(Dp(100f), Dp(50f)))
Text(text = "hello,jetpack compose!")
}
}
通过Column
的源码可以看到我们还可以传递如下几个参数:
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {
...
}
参数 | 类型 | 默认值 | 含义 |
---|---|---|---|
modifier | Modifier | Modifier | 布局的修饰符 |
contentAlignment | Alignment | Alignment.TopStart | Box 内的默认对齐方式 |
propagateMinConstraints | Boolean | false | 传入的最小约束是否应传递给内容。 |
4. BoxWithConstraints
如需了解来自父项的约束条件并相应地设计布局,您可以使用
BoxWithConstraints
。您可以在内容 lambda 的作用域内找到测量约束条件。
BoxWithConstraints
与 Box
使用方式完全一致,只是如官方所说,可以测量约束条件,例如:
@Composable
fun MainPage1() {
BoxWithConstraints {
Text("My minHeight is $maxHeight while my maxWidth is $maxWidth")
}
}
在其作用域内可以拿到 BoxWithConstraints
的最大最小宽高信息。
5. ConstraintLayout
ConstraintLayout
其实就是Xml布局中的 ConstraintLayout
,我们来看官方的描述
ConstraintLayout
有助于根据可组合项的相对位置将它们放置在屏幕上,它是使用多个嵌套Row
、Column
、Box
和自定义布局元素的替代方案。在实现对齐要求比较复杂的较大布局时,ConstraintLayout
很有用。
注意:在 View 系统中,建议使用
ConstraintLayout
来创建复杂的大型布局,因为扁平视图层次结构比嵌套视图的性能更好。不过,这在 Compose 中不是什么问题,因为它能够高效地处理较深的布局层次结构。
注意:是否将
ConstraintLayout
用于 Compose 中的特定界面取决于开发者的偏好。在 Android View 系统中,使用ConstraintLayout
作为构建更高性能布局的一种方法,但这在 Compose 中并不是问题。在需要进行选择时,请考虑ConstraintLayout
是否有助于提高可组合项的可读性和可维护性。
可以看出,虽然官方提供了ConstraintLayout
,但并不推荐在Compose
中使用,xml中使用ConstraintLayout
的根本目的是为了减少视图嵌套层级从而提升android
的页面绘制性能,在Compose
中不存在视图嵌套这一概念,所以是否使用ConstraintLayout
,需要考虑个人习惯和 ConstraintLayout
是否有助于提高可组合项的可读性和可维护性。
在使用ConstraintLayout
前,需要在 build.gradle
中添加以下依赖项:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha08"
Compose
中的 ConstraintLayout
支持 DSL:
- 引用是使用
createRefs()
或createRefFor()
创建的,ConstraintLayout
中的每个可组合项都需要有与之关联的引用。 - 约束条件是使用
constrainAs()
修饰符提供的,该修饰符将引用作为参数,可让您在主体 lambda 中指定其约束条件。 - 约束条件是使用
linkTo()
或其他有用的方法指定的。 parent
是一个现有的引用,可用于指定对ConstraintLayout
可组合项本身的约束条件。
依旧看下实例:
@Composable
fun MainPage() {
ConstraintLayout(Modifier.size(200.dp)) {
val (button, text) = createRefs()
Button(
onClick = { },
modifier = Modifier.constrainAs(button) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
},
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.secondary,
contentColor = Color.White
)
) {
Text("Button")
}
Text("Text", Modifier.constrainAs(text) {
top.linkTo(button.top)
})
}
}
可以看出,用法和xml中基本一致,代码中button
被约束到视图中心,text
的顶部对齐button
的顶部。
6. Spacer
一个空白的视图,官方并未提供类似于Xml中margin
的属性,可能推荐用这个替代吧。例如:
@Composable
fun MainPage() {
Row {
Box(Modifier.size(100.dp).background(Color.Red))
Spacer(Modifier.width(20.dp))
Box(Modifier.size(100.dp).background(Color.Magenta))
Spacer(Modifier.weight(1f))
Box(Modifier.size(100.dp).background(Color.Black))
}
}
二、最后
好记性不如烂笔头,初识 Jetpack Compose
系列是我自己的学习笔记,在加深知识巩固的同时,也可以锻炼一下写作技能。文章中的内容仅作参考,如有问题请留言指正。
2.滚动视图
上面说到 Row
和 Column
有如果子视图超出父视图边界,则无法展示的问题;在xml中一般使用ScrollView
以支持视图滚动,相应的,在Compose
中可以由LazyRow
、LazyColumn
实现,但他俩的功能不仅仅只是用来实现视图滚动,所以在本文就不展开了,LazyRow
、LazyColumn
预计将会有后续的widget
篇中具体描述。