Jetpack Compose中的布局组件、状态栏高度padding

前言

Jetpack Compose 提供了一系列用于构建用户界面的布局组件,这些组件可以帮助您创建各种复杂的布局结构。

对应关系

View Jetpack Compose
FrameLayout Box& Modifier
RelativeLayout Box & Modifier
LinearLayout Row, Column
ConstraintLayout ConstraintLayout 移植到了 Compose 中
RecyclerView LazyColumn or LazyRow
ScrollView Modifier.verticalScroll() or Modifier.horizontalScroll()

层叠布局

Box: Box 是一个简单的布局组件,用于在单个平面上叠加子元素。

您可以使用 contentAlignment 属性来指定子元素的对齐方式。

默认

1
2
3
4
5
6
7
8
9
10
11
12
@Composable
fun OverlayLayoutExample() {
Box(
modifier = Modifier
.padding(16.dp)
.size(200.dp)
.background(Color.LightGray),
contentAlignment = Alignment.Center
) {
Text(text = "Overlay Text")
}
}

双向滚动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Box(
Modifier
.size(200.dp)
.horizontalScroll(rememberScrollState())
.verticalScroll(rememberScrollState())

) {
Image(
modifier = Modifier
.padding(10.dp)
.size(400.dp)
.background(color = Color.Yellow)
.clip(shape = CircleShape),
painter = painterResource(id = R.drawable.logo),
contentDescription = null,
contentScale = ContentScale.Crop,
)
}

垂直布局

Column: Column 组件用于垂直排列子元素。

默认

您可以使用 verticalArrangement 属性来指定子元素的垂直排列方式,使用 horizontalAlignment 属性来指定子元素的水平对齐方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Composable
fun VerticalLayoutExample() {
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Item 1")
Text(text = "Item 2")
Text(text = "Item 3")
}
}

纵向滚动

1
2
3
Column(Modifier.verticalScroll(rememberScrollState())) {

}

横向滚动

1
2
3
Column(Modifier.horizontalScroll(rememberScrollState())) {

}

双向滚动

1
2
3
4
5
6
Column(
Modifier
.horizontalScroll(rememberScrollState())
.verticalScroll(rememberScrollState())
) {
}

水平布局

Row: Row 组件用于水平排列子元素,允许您指定水平排列方式和垂直对齐方式。

默认

默认不能滚动,会挤压最后的组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Composable
fun HorizontalLayoutExample() {
Row(
modifier = Modifier
.padding(16.dp) // 设置整个 Row 的内边距
.fillMaxWidth(), // 撑满父容器的宽度
horizontalArrangement = Arrangement.SpaceEvenly, // 子元素的水平排列方式
verticalAlignment = Alignment.CenterVertically // 子元素的垂直对齐方式
) {
Text(text = "Item 1")
Text(text = "Item 2")
Text(text = "Item 3")
}
}

横向滚动

1
2
3
Row(Modifier.horizontalScroll(rememberScrollState())) {

}

纵向滚动

1
2
3
Row(Modifier.verticalScroll(rememberScrollState())) {

}

双向滚动

1
2
3
4
5
6
Row(
Modifier
.horizontalScroll(rememberScrollState())
.verticalScroll(rememberScrollState())
) {
}

约束布局

ConstraintLayout: ConstraintLayout 是一个强大的布局组件,允许您使用约束关系来定义子元素之间的位置关系。

这使得创建复杂的布局结构变得更加灵活和简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Composable
fun ConstraintLayoutExample() {
ConstraintLayout {
val (text1, text2) = createRefs()

Text(
text = "Text 1",
modifier = Modifier.constrainAs(text1) {
top.linkTo(parent.top)
start.linkTo(parent.start)
}
)

Text(
text = "Text 2",
modifier = Modifier.constrainAs(text2) {
top.linkTo(text1.bottom)
start.linkTo(parent.start)
}
)
}
}

流式布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Preview
@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun FlowRowSimpleUsageExample() {
FlowRow(
modifier = Modifier.padding(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
maxItemsInEachRow = 3
) {
val itemModifier = Modifier
.clip(RoundedCornerShape(8.dp))
Box(modifier = itemModifier.height(60.dp).width(60.dp).background(Color.Red))
Box(modifier = itemModifier.height(60.dp).fillMaxWidth(0.7f).background(Color.Blue))
Box(modifier = itemModifier.height(60.dp).weight(1f).background(Color.Magenta))
Box(modifier = itemModifier.height(60.dp).fillMaxWidth(0.7f).background(Color.Blue))
}
}

其中

  • horizontalArrangement 水平间距
  • verticalArrangement 垂直间距

Surface(表面)

Surface 是一个容器组件,用于包裹其他组件并为其提供样式、背景色等属性。

Surface 可以帮助您创建具有不同样式的可视化元素,并为其提供外观属性。

1
2
3
4
5
6
7
8
Surface(
color = Color.Blue, // 设置 Surface 的背景色为蓝色
modifier = Modifier.fillMaxSize() // 填充父级的大小
) {
// 在 Surface 内部放置其他组件
// 这里放置了一个文本组件作为示例
Text(text = "Hello, Surface!", color = Color.White)
}

设置背景形状

1
2
3
4
5
6
7
Surface(
modifier = Modifier.size(300.dp),
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colorScheme.background
) {
Text("文字")
}

Card(卡片)

Card 是一个容器组件,类似于 Surface,用于包裹其他组件并为其提供样式、背景色等属性。

Card 组件通常用于显示单个元素或组件,并为其添加阴影效果以使其在界面上突出显示。

1
2
3
4
5
Card(
modifier = Modifier.padding(16.dp)
) {
Text("Card Content")
}

Surface和Card的区别

SurfaceCard 都是用来定义 UI 元素的容器,它们之间有几个区别:

  1. 默认样式

    • Surface 默认情况下没有圆角背景是白色。
    • Card 默认情况下有圆角背景是灰色。
  2. 功能和用途

    • Surface 是一个基本的容器,用于在屏幕上绘制内容。它提供了绘制颜色、形状、边框等的基本功能。

      通常用于创建自定义的UI元素,例如背景、容器等。

      Surface 内部是个Box,内容放在Box内。

    • Card 是一个更高级的容器,提供了带阴影、圆角等样式的卡片视图。

      通常用于显示单个项目或内容,例如列表项、详细信息卡等。

      Card内部是个SurfaceSurface下是个Column,内容放在Column内。

  3. 交互性

    • 默认都没有点击效果,添加Modifier.clickable { }都有点击的涟漪效果。

Surface

1
2
3
4
5
6
7
8
9
10
fun Surface(
modifier: Modifier = Modifier,
shape: Shape = RectangleShape,
color: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = contentColorFor(color),
tonalElevation: Dp = 0.dp,
shadowElevation: Dp = 0.dp,
border: BorderStroke? = null,
content: @Composable () -> Unit
)

Card

1
2
3
4
5
6
7
8
fun Card(
modifier: Modifier = Modifier,
shape: Shape = CardDefaults.shape,
colors: CardColors = CardDefaults.cardColors(),
elevation: CardElevation = CardDefaults.cardElevation(),
border: BorderStroke? = null,
content: @Composable ColumnScope.() -> Unit
)

状态栏高度

1
2
3
4
5
6
7
Box(
modifier = Modifier
.statusBarsPadding()
.fillMaxSize(),
) {

}