一、标准布局
- 标准布局组件
Column 行 相当于LinearLayout vertical方向
row 列 相当于LinearLayout horizontal方向
BOX 相当于FrameLayout 需要明确的指出控件的具体位置
Surface可以设置一个形状然后再包裹对应的控件如设置一个圆形的图片
Surface(modifier = Modifier.size(50.dp),shape = CircleShape) {
Image()
}
2.修饰符(modifier) > 修饰符是具有顺序的(如marage可以使用padding来代替 先进行一次padding然后设置背景在设置一次padding,背景不会包含第一次的padding)
3.slots API 可以设置标题菜单栏等 如TopAppBar
4.列表
1.布局可以通过设置verticalScroll和horizontalScroll来使它进行滚动相当于ScrollView
2.LazyColumn和LazyRow是可以懒加载的列表只加载显示的部分 相当于Recyclerview
二、自定义布局
1.对于单个控件可以在修饰符layout中进行自定义使用measurable.measure(constraints) 进行一次测量拿到尺寸的具体属性并重新设置控件的宽高,然后再layout中设置显示内容的开始位置
Text(modifier = Modifier.firstBaselineToTop(24.dp))
fun Modifier.firstBaselineToTop(firstBaselineToTop: Dp) = this.then(
layout { measurable, constraints ->
//测量元素
val placeable = measurable.measure(constraints)
//测量之后,获取元素的高度
val firstBaseline = placeable[FirstBaseline]
//计算元素的新Y
val placeableY = firstBaselineToTop.roundToPx() - firstBaseline
val height = placeable.height + placeableY
layout(placeable.width,height){
//设置显示的位置
placeable.placeRelative(0,placeableY)
}
}
)
- 对于多个控件则直接在@Composable方法体内的Layout方法中进行重新排列绘制相对于上面的单个控件这里返回的是measurables, constraints都是集合
MyOwnColum (){
Text("MyOwnColum")
Text("places items")
Text("vertically")
Text("we've done it by hand!")
}
@Composable
fun MyOwnColum(modifier: Modifier = Modifier,content: @Composable () -> Unit) {
Layout(modifier = modifier, content = content){ measurables, constraints ->
//测量的元素集合
val placeables = measurables.map { measurable->
measurable.measure(constraints)
}
var yPosition = 0
//布局的大小
layout(constraints.maxWidth, constraints.maxHeight) {
placeables.forEach{ placeable ->
placeable.placeRelative(0,yPosition)
//累加Y 这样就是一行一行显示
yPosition += placeable.height
}
}
}
}
三、约束布局
(ConstraintLayout 相当于RelativeLayout 设置约束有点像IOS)
1.不是标准布局控件所以需要导入相应的支持
implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
2.使用createRefs创建约束属性在修饰符在constrainAs方法内使用linkTo方法创建约束
ConstraintLayout {
val (button,text) = createRefs()
Button(onClick = {}, modifier = Modifier.constrainAs(button){
top.linkTo(parent.top, margin = 16.dp)
}) {
Text("button")
}
Text(text = "Text", modifier = Modifier.constrainAs(text){
top.linkTo(button.bottom, margin = 16.dp)
centerHorizontallyTo(parent)
})
}
3.可以使用ConstraintSet方法将一些约束提取出来,并在ConstraintLayout 方法上进行设置,控件在修饰符上使用layoutId指定标识
private fun decoupledConstraints(margin:Dp) :ConstraintSet{
return ConstraintSet {
val button = createRefFor("button")
val text = createRefFor("text")
constrain(button){
top.linkTo(parent.top, margin = margin)
}
constrain(text){
top.linkTo(button.bottom, margin = margin)
}
}
}
BoxWithConstraints {
val constraints = if (maxWidth < maxHeight) {
decoupledConstraints(16.dp)
}else{
decoupledConstraints(160.dp)
}
ConstraintLayout(constraints) {
Button(onClick = {}, modifier = Modifier.layoutId("button")) {
Text("button")
}
Text(text = "Text", modifier = Modifier.layoutId("text"))
}
}
四、Intrinsics
可以在布局中去指定测量的时候按最大或者最小值去测量,如下面的分隔线设置的是最大宽度,当时布局中使用intrinsics指定测量按满足子控件的最大宽度显示
Row(modifier = modifier.height(IntrinsicSize.Min)) {
Text(
"Hi", modifier = Modifier
.weight(1f)
.padding(start = 4.dp)
.wrapContentWidth(Alignment.Start)
)
VerticalDivider(color = Color.Black, modifier = Modifier
.fillMaxHeight()
.width(1.dp))
Text(
"there", modifier = Modifier
.weight(1f)
.padding(start = 4.dp)
.wrapContentWidth(Alignment.End)
)
}
其他
image组件可以导入implementation("io.coil-kt:coil-compose:1.3.0")直接加载网络图片
Image(painter = rememberImagePainter(data = "URL"),contentDescription = null)