Jetpack Compose布局(一) - 布局基础知识
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack Compose布局(一) - 布局基础知识相关的知识,希望对你有一定的参考价值。
参考技术A 在上篇 《Jetpack Compose技术快速上手》 一文中简单介绍了Compose,那么这边我们就来学习下Compose的布局。由于布局这块涉及内容较多,会分开写。
布局主要包括:布局基础知识、 Material组件和布局 、 自定义布局 、 Compose中使用ConstraintLayout 。
本文重点讲解 布局基础知识 。
主要涉及: 可组合函数、标准布局元素、基本组件、布局模型、修饰符、槽位布局 。如下图:
可组合函数是 Compose 的基本构建块,返回值是 Unit 的函数,用于描述界面中的某一部分,该函数可接收参数。
组合函数中可包含多个界面元素。
其基本格式为:
在Compose中标准的布局元素有三个: Box 、 Column 、 Row 。
Box
重叠布局,类似android View系统中的FramLayout布局,元素会重叠显示,其原型定义如下:
例子
Column
垂直布局,在界面元素垂直方向依次排列。源码中定义如下:
实例
Row
元素水平方向分布,源码中定义:
示例
Jetpack Compose中组件库包括:compose-ui和material。很多常用基本组件都是在material库中,Compose-ui中组件很少:Image、BasicTextField(输入框)。
示例:
在对标准布局元素和组件有了一定了解后,我们来看下Compose的布局流程。
首先Compose布局是一个界面树,从树的根节点开始依次要求其子节点对自身进行测量,然后递归完成所有子节点的测量,并将约束条件沿着树向下传递给子节点,并将测量的尺寸和放置指令依次向根节点传递。
以下面可组合函数为示例:
其布局过程如下图示:
在Compose布局中修饰符至关重要,您可以使用修饰符来修饰或扩充可组合项。常用的修饰符如下:
修饰符扩展
除了使用Compose提供的修饰符外,我们也可以扩展函数自定义修饰符,具体方式可以参考 Jetpack Compose布局(三) 一文中讲的 扩展布局修饰符 。
强调:修饰符的使用是有顺序的
强调:修饰符的使用是有顺序的
强调:修饰符的使用是有顺序的
例如,将上例的background和padding顺序调换下,就会如下图效果,仔细看两图的顶部边距,会发现区别
Compose中提供了固定槽位的可组合项,以简化界面元素,这些主要在 androidx.compose.material:material 库中,如: Drawer 、 FloatingActionButton 、 TopAppBar 等。
Material 组件大量使用槽位 API,这是 Compose 引入的一种模式,它在可组合项之上带来一层自定义设置。这种方法使组件变得更加灵活,因为它们接受可以自行配置的子元素,而不必公开子元素的每个配置参数。槽位会在界面中留出空白区域,让开发者按照自己的意愿来填充。如下图 TopAppBar 的槽位。
关于槽位内容会在 Jetpack Compose布局(二) 中做详细讲解,本篇就不进行深入讨论了。
欢迎留言,一起学习,共同进步!
初识 Jetpack Compose :布局
一、布局
官网对于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
篇中具体描述。
以上是关于Jetpack Compose布局(一) - 布局基础知识的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack Compose学习—— Jetpack compose基础布局
Android Jetpack Compose学习—— Jetpack compose基础布局