本篇和上一篇基本差不多,都是对原来的行列布局进行修改,毕竟ConstraintLayout十分滴好用。
1、页面布局优化
这次先放预览图
本篇要实现的就是优化一下LazyColumn中item的布局,就是每一个小项的布局。
注意:这里因为没在Entities文件中对Chapter数据类进行修改调整,所以就没加字数的数据列。
首先定义一个数据集:
val chapter:List<Chapter> = listOf(
Chapter(0,1,1,"第1章","","2023-11-30 8:00:00"),
Chapter(1,1,2,"第2章","","2023-11-31 8:00:00"),
Chapter(2,1,3,"第3章","","2023-11-32 8:00:00"),
)
这里随便写了点数据,主要是为了看显示效果嘛,之后这些数据肯定是从数据库来的。
之后我们要做的就是列表块,如图:
话不多说,直接放代码,经过上一篇的学习相信你已经会操作约束布局了。
LazyColumn(modifier = Modifier.fillMaxSize()){
items(chapter){
ConstraintLayout(modifier = Modifier.fillMaxWidth())
{
val (chapterNumber, chapterName, fontNumber, updateTime) = createRefs()
Text(text = it.chapterName!!,
modifier = Modifier.constrainAs(chapterNumber){
top.linkTo(parent.top, margin = 8.dp)
start.linkTo(parent.start, margin = 24.dp)
},
fontSize = 20.sp)
Text(text = it.chapterName!!,
modifier = Modifier.constrainAs(chapterName){
baseline.linkTo(chapterNumber.baseline)
start.linkTo(chapterNumber.end, margin = 16.dp)
},
fontSize = 20.sp)
Text(text = "3562字",
modifier = Modifier.constrainAs(fontNumber){
top.linkTo(chapterNumber.bottom, margin = 4.dp)
start.linkTo(chapterNumber.start, margin = 16.dp)
},
fontSize = 16.sp)
Text(
text = it.lastUpdateTime,
modifier = Modifier.constrainAs(updateTime){
baseline.linkTo(fontNumber.baseline)
end.linkTo(parent.end, margin = 16.dp)
},
fontSize = 16.sp
)
}
}
}
从代码中可以看到,我们遍历的数据列表是我们刚刚随便写的那个列表,而在括号内依然要用it来使用它。
这段代码也提供了一个参考,当之后有了数据库后,基本都是这种方式来获取某个参数了。
2、clickable()函数的使用
再提一个关键点
在主页时,我们通过Card的onClick属性来实现页面跳转,但是此时我们并没有Card布局,我们只有一个ConstraintLayout,它的属性里面并没有onClick这个属性。
那此时我们想通过点击列表项进行跳转的话,要怎么操作?
其实,modifier中提供了一个.clickable方法,只需要通过这个我们就可以进行跳转了。
比如我在约束布局中添加:
ConstraintLayout(modifier = Modifier
.fillMaxWidth()
.clickable {
navController.navigate("write_text_page/fic")
}){}
这两行代码就完成了页面的跳转。
当然,这里的writetextpage还没写,之后会有。
到这里就算完成本页面的优化了。
3、ConstraintLayout约束解耦
ConstraintLayout的基本使用相信大家都差不多会了,但是当控件比较多的时候,代码写在一块就显得非常的拥挤,比如我们要做的写文本的界面:
从上图可以看到,我们在工具栏topbar上安放了很多功能键,如果这些还是写在一个文件中,那么它的代码会非常长,可读性很差。
这时就要用到ConstraintLayout的解耦约束了,简单说就是把他的布局和约束单独写成一个函数,这样在主页面内只需要调用函数名即可。
接下来上WriteTextPage的topbar代码:
@Composable
fun WriteTextTopBar() {
val constraintSet = decoupledConstraints(0.dp)
ConstraintLayout(constraintSet, modifier = Modifier.fillMaxWidth()) {
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_back")
) {
Image(
painter = painterResource(id = R.drawable.btn_back),
contentDescription = "add a book"
)
}
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_chapter_list")
) {
Image(
painter = painterResource(id = R.drawable.btn_chapter_list),
contentDescription = "add a book"
)
}
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_save")
) {
Image(
painter = painterResource(id = R.drawable.btn_save),
contentDescription = "add a book"
)
}
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_undo")
) {
Image(
painter = painterResource(id = R.drawable.btn_undo),
contentDescription = "add a book"
)
}
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_redo")
) {
Image(
painter = painterResource(id = R.drawable.btn_redo),
contentDescription = "add a book"
)
}
Text(modifier = Modifier.layoutId("font_num"),
text = "4000字",
fontSize=20.sp)
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_item")
) {
Image(
painter = painterResource(id = R.drawable.btn_item),
contentDescription = "add a book"
)
}
IconButton(
onClick = { },
//通知设置layoutId实现控制约束
modifier = Modifier
.height(50.dp)
.width(40.dp)
.layoutId("btn_add")
) {
Image(
painter = painterResource(id = R.drawable.btn_add),
contentDescription = "add a book"
)
}
}
}
上半部分代码主要绑定组件,注意ConstraintLayout的传参有了些许变化。
下半部分:
// 约束布局函数只负责声明约束,不管其他的属性
private fun decoupledConstraints(margin: Dp): ConstraintSet {
return ConstraintSet {
val btn_back= createRefFor("btn_back")
constrain(btn_back){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
}
val btn_chapter_list= createRefFor("btn_chapter_list")
constrain(btn_chapter_list){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(btn_back.end)
}
val btn_save= createRefFor("btn_save")
constrain(btn_save){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(btn_chapter_list.end)
}
val btn_undo= createRefFor("btn_undo")
constrain(btn_undo){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(btn_save.end)
}
val btn_redo= createRefFor("btn_redo")
constrain(btn_redo){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(btn_undo.end)
}
val btn_add = createRefFor("btn_add")
constrain(btn_add){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
end.linkTo(parent.end)
}
val btn_item= createRefFor("btn_item")
constrain(btn_item){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
end.linkTo(btn_add.start)
}
val font_num= createRefFor("font_num")
constrain(font_num){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(btn_redo.end)
end.linkTo(btn_item.start)
}
}
}
下半部分代码只负责控制约束,这样就将约束和布局解藕了。
注意:
val btn_back= createRefFor("btn_back")
constrain(btn_back){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
}这其中加粗的地方都要一致,不可val btnback= createRefFor("btn_back"),这样就会导致图标不显示。
在本来的页面函数中只需要调用即可:
Scaffold(modifier = Modifier.fillMaxWidth(),
topBar = {
TopAppBar(modifier = Modifier.height(50.dp), // 设置高度为 50dp
title = { Text("") },
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = colorResource(id = R.color.toolbar_color)
),
actions = {
WriteTextTopBar()
})
}
) {}
这样工具栏的效果就实现了!