Jetpack Compose布局组件&列表组件
1. 线性布局
概述
Compose 中的线性布局对应的是Android传统视图中的LinearLayout,不一样的地方是,Compose根据Orientation的不同又将布局分为Column和Row, Column对应传统视图LinearLayout中orientation = “vertical”的情况,Row对应传统视图LinearLayout中orientation = “horizontal”的情况.由于两者内部元素在父容器中的布局和对其方式不同,分成两个组件有助于提供类型安全的Modifier修饰符。
Column = 垂直
Row = 横向
1.1 Column
@Composable
inline fun Column(
modifier: Modifier = Modifier, // 修饰符
verticalArrangement: Arrangement.Vertical = Arrangement.Top, //verticalArrangement 参数来定位子项在 Column 中的垂直位置。
horizontalAlignment: Alignment.Horizontal = Alignment.Start, // horizontalAlignment 参数来定位子项在 Column 中的水平位置
content: @Composable ColumnScope.() -> Unit
) {
Arrangement有如下枚举值:
Arrangement.Start // 子view排列在头部
Arrangement.End // 子view排列在尾部
Arrangement.Center // 子view排列在中间
Arrangement.SpaceBetween // 首尾没有空隙,且子view之间均匀分散
Arrangement.SpaceAround // 首尾空隙是每个子view之间空隙的一半
Arrangement.SpaceEvenly // 让每个子view之间的空隙均匀分散,包括首尾
垂直排列 Column
ComposeDemoTheme {
Column(
modifier = Modifier
.border(1.dp, color = Color.Red)
.size(150.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = "Hello World",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Column 是垂直",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Column 是垂直",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
垂直排列 Column 改变子的垂直方向和水平方向的位置
ComposeDemoTheme {
Column(
modifier = Modifier
.border(1.dp, color = Color.Red)
.size(150.dp),
verticalArrangement = Arrangement.Top, // 改变子的垂直位置为顶部
horizontalAlignment = Alignment.End // 改变子的水平位置为后
) {
Text(
text = "Hello World",
style = MaterialTheme.typography.bodyLarge,
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Column 是垂直",
style = MaterialTheme.typography.bodyLarge,
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Column 是垂直",
style = MaterialTheme.typography.bodyLarge,
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
1.1 Row
@Composable
inline fun Row(
modifier: Modifier = Modifier,//修饰符
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,//水平对齐方式
verticalAlignment: Alignment.Vertical = Alignment.Top,//垂直对齐方式
content: @Composable RowScope.() -> Unit
){
}
水平排列 Row
ComposeDemoTheme {
Row(
modifier = Modifier
.border(5.dp, color = Color.Red)
.size(350.dp),
) {
Text(
text = "Hello World",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.absolutePadding(10.dp,10.dp,0.dp,0.dp)
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Row是水平",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.absolutePadding(10.dp,10.dp,0.dp,0.dp)
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = "Row是水平",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.absolutePadding(10.dp,10.dp,0.dp,0.dp)
// modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
使用 horizontalArrangement 和 verticalAlignment 让内容居中
给子内容添加间距使用 Arrangement.spacedBy
2.Box布局
inline fun Box(
modifier: Modifier = Modifier, // 修饰符
contentAlignment: Alignment = Alignment.TopStart, // 内容对齐方式(水平和垂直),默认是左上角(LTR情况下)
propagateMinConstraints: Boolean = false, // 是否将最小约束传给内部View,如果设置为true,则内容会填满Box本身
content: @Composable BoxScope.() -> Unit // 内部布局
)
box 代码示例
fun BoxDemo() {
ComposeDemoTheme {
Box(
modifier = Modifier
.size(300.dp)
.background(Color.Blue),
contentAlignment = Alignment.Center,
) {
Text(
text = "1", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
.align(Alignment.Center)
)
Text(
text = "2", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
.align(Alignment.BottomEnd)
)
Text(
text = "3", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
.align(Alignment.BottomStart)
)
Text(
text = "4", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
.align(Alignment.TopStart)
)
Text(
text = "5", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
.align(Alignment.TopEnd)
)
}
}
}
Box 添加 propagateMinConstraints = true 子会填充满Box
3.约束布局
Compose ConstraintLayout
约束布局主要应用在构建复杂布局,避免使用Column
、Row
、Box
多层嵌套,同时也能提高开发效率。
开始使用之前需要添加对ConstraintLayout
的依赖:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
@Composable
inline fun ConstraintLayout(
modifier: Modifier = Modifier,
optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
crossinline content: @Composable ConstraintLayoutScope.() -> Unit
)
fun ConstraintLayoutDemo() {
ConstraintLayout(modifier = Modifier.size(500.dp)) {
//为每个子元素创建引用
val (buttonRef, textRef) = createRefs()
Button(
onClick = { /* Do something */ },
//将组合函数和引用关联
modifier = Modifier.constrainAs(buttonRef) {
//指定约束条件,现有引用parent是指ConstraintLayout
top.linkTo(parent.top, margin = 16.dp)
}
) {
Text("Button")
}
Text(
text = "Text",
Modifier.constrainAs(textRef) {
top.linkTo(buttonRef.bottom, margin = 16.dp)
// centerAround(buttonRef.end) //自己中间对齐谁的哪边
centerHorizontallyTo(parent) //水平居中
}
)
}
}
通过linkTo
函数将view
与其他view
或者parent
约束。这里的parent
指的就是ConstraintLayout
本身。
constrainAs
函数中的start
、top
、end
、bottom
分别代表view
的左、上、右、下四条边,linkTo
表示相互作用。
供居中对齐,centerTo
、centerHorizontallyTo
、centerVerticallyTo
fun ConstraintLayoutDemo2() {
ConstraintLayout(modifier = Modifier.size(400.dp, 100.dp)) {
val (imgRef, text1Ref, text2Ref, text3Ref) = createRefs()
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "image",
modifier = Modifier
.size(80.dp)
.constrainAs(imgRef) {
top.linkTo(parent.top, margin = 10.dp)
start.linkTo(parent.start, margin = 10.dp)
},
contentScale = ContentScale.Crop
)
Text(
text = "约束布局标题",
color = Color.Blue,
fontSize = 20.sp,
textDecoration = TextDecoration.Underline,
modifier = Modifier
.constrainAs(text1Ref) {
start.linkTo(imgRef.end, margin = 10.dp)
top.linkTo(imgRef.top)
}
)
Text(
text = "约束布局副标题",
color = Color.Blue,
fontSize = 15.sp,
textDecoration = TextDecoration.Underline,
modifier = Modifier
.constrainAs(text2Ref) {
start.linkTo(text1Ref.start)
top.linkTo(text1Ref.bottom, margin = 20.dp)
}
)
Text(
text = "垂直居中",
color = Color.Blue,
fontSize = 15.sp,
textDecoration = TextDecoration.Underline,
modifier = Modifier
.constrainAs(text3Ref) {
end.linkTo(parent.end, margin = 20.dp)
centerVerticallyTo(parent)
}
)
}
}
4.lazycolumn 纵向列表
fun lazyColumnDemo() {
val list = mutableStateListOf<String>()
repeat(20) {
list.add(it.toString())
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(24.dp),//item 间距
contentPadding = PaddingValues(start = 5.dp, end = 5.dp),
) {
item {
Text(
text = "列表头布局",
fontSize = 20.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.size(400.dp, 100.dp)
.background(Color.Yellow)
)
}
items(list) {
ConstraintLayoutDemo3(it)
}
}
}
修改 reverseLayout = true 将列表顺序反转
fun lazyColumnDemo() {
//可触发重组的List
val list = mutableStateListOf<String>()
repeat(20) {
list.add(it.toString())
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(24.dp),//item 间距
contentPadding = PaddingValues(start = 5.dp, end = 5.dp),
reverseLayout = true
) {
item {
Text(
text = "列表头布局",
fontSize = 20.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.size(400.dp, 100.dp)
.background(Color.Yellow)
)
}
items(list) {
ConstraintLayoutDemo3(it)
}
}
}
5.LazyRow 横向列表
用法与LazyColumn 一样
fun lazyRowDemo() {
val list = mutableStateListOf<String>()
repeat(20) {
list.add(it.toString())
}
LazyRow(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(24.dp),//item 间距
contentPadding = PaddingValues(top = 20.dp),
) {
item {
Text(
text = "头",
fontSize = 15.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Yellow)
)
}
items(list) {
Text(
text = it,
fontSize = 20.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
)
}
}
}
6.LazyVerticalGrid
fun LazyVerticalGridDemo() {
val list = mutableStateListOf<String>()
repeat(20) {
list.add(it.toString())
}
LazyVerticalGrid(
columns = GridCells.Fixed(3),
horizontalArrangement = Arrangement.spacedBy(10.dp),//item 间距
verticalArrangement = Arrangement.spacedBy(10.dp),
contentPadding = PaddingValues(10.dp)
) {
item {
Column {
Button(modifier = Modifier.fillMaxWidth(), onClick = { list.add("21") }) {
Text(text = "新增数据")
}
}
}
items(list) {
Text(
text = it,
fontSize = 20.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.size(50.dp, 50.dp)
.background(Color.Gray)
)
}
}
}