Android JetPack ComPose —— 布局控件 Column、Row、Box 介绍,为什么没有 Margin 属性?

语言: CN / TW / HK

本篇文章介绍 Compose 的布局控件 ColumnRowBox,在 Android XML 模式开发中,常用的布局控件有 LinearLayoutRelativeLayoutFrameLayout 以及 ConstraintLayout, Compose 没有延用之前的布局设计,而是提供了全新的布局控件,不仅实现了 XML 模式的相关功能并且更加灵活好用。

layout-column-row-box.svg

先了解 Modifier:(View 的常用属性设定)

Compose 开发中,设计者将 View 的通用属性设置封装成接口类 Modifier 给开发者统一调用,比如设置 ViewBackgroundWidth / HeightPaddingClickable 等等,介绍布局控件之前先来简单了解 Modifier,后续会有专门的文章来详细讲解。

属性介绍

```kotlin @Composable fun ModifierTestView() { Text( text = "Hello Compose!", modifier = Modifier .fillMaxWidth() .fillMaxHeight() .width(100.dp) .height(100.dp) .padding() .background( color = colorResource(id = R.color.black), shape = RoundedCornerShape(10.dp) ) .clickable {

        }
)

}

``` - fillMaxWidth() / fillMaxHeight() 设置填充最大宽高,也可以用 fillMaxSize() 代替 - width() / height() 设置控件宽高,也可以用 size() 代替 - padding 设置控件的内边距 - background() 设置背景
- color:背景颜色
- shape:设置裁剪(RoundedCornerShape(10.dp) 圆角 10dp) - clickable{} 设置点击监听


Modifier 作为参数传递,统一设定

```kotlin @Composable fun SquareView() { ModifierTestView( modifier = Modifier .width(100.dp) .height(100.dp) ) }

@Composable fun ModifierTestView(modifier: Modifier) { Text( text = "Hello Compose!", modifier = Modifier .width(100.dp) .height(100.dp) .padding() .background(colorResource(id = R.color.black)) .clickable {

        }
)

} ```

Column 垂直布局:(LinearLayout 垂直方向)

属性介绍

kotlin @Composable inline fun Column( modifier: Modifier = Modifier, verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, content: @Composable ColumnScope.() -> Unit ) - modifier:常用属性设定 - verticalArrangement:垂直方向设定 - horizontalAlignment:水平方向设定 - content:添加布局内的 View

代码示例

kotlin @Composable fun ColumnView() { Column( modifier = Modifier .fillMaxSize() .background(Color.White), verticalArrangement = Arrangement.Top ) { Text(text = "垂直排列 0") Text(text = "垂直排列 1") Text(text = "垂直排列 2") Text(text = "垂直排列 3") } } column_view.png


ColumnView 方向设定

Column 垂直方向使用 Arrangement 设置,水平方向使用 Alignment 设置。 - verticalArrangement(垂直方向设定)
1. .Top:子 View 居于 Column 垂直方向居上 2. .Bottom:子 View 居于 Column 垂直方向居下 3. .Center:子 View 居于 Column 垂直方向居中 4. .SpaceEvenly:子 View 平均分配 Column 垂直(高度) 5. .SpaceAround:子 View 平均分配 Column 垂直(高度),但是头部和底部 子 View 基于 Column 头部和底部的边距是平分高度的一半 6. .SpaceBetween:子 View 平均分配 Column 垂直(高度),头部和底部子 View 贴着 Column头部底部,没有边距 - horizontalAlignment(水平方向设定)
1. .Start:子 View 居于 Column 开始绘制的边界(水平方向左对齐) 2. .End:子 View 居于 Column 结束绘制的边界(水平方向右对齐) 3. .CenterHorizontally:子 View 居于 Column 水平方向居中

### 看示例图更好理解
column.gif
EqualWeight 在正式版发布后,使用了子 View .weight() 方式代替,下面会详细介绍。

Row 水平布局:(LinearLayout 水平方向)

属性介绍

kotlin @Composable inline fun Row( modifier: Modifier = Modifier, horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, verticalAlignment: Alignment.Vertical = Alignment.Top, content: @Composable RowScope.() -> Unit ) - modifier:常用属性设定 - horizontalArrangement:水平方向设定 - verticalAlignment:垂直方向设定 - content:添加布局内的 View

代码示例

kotlin @Composable fun RowView() { Row( modifier = Modifier .fillMaxSize() .background(Color.White), verticalAlignment = Alignment.Top ) { Text(text = "水平排列 0") Text(text = "水平排列 1") Text(text = "水平排列 2") Text(text = "水平排列 3") } }

row.png

RowView 方向设定

Row 水平方向使用 Arrangement 设置,垂直方向使用 Alignment 设置。 - horizontalArrangement(水平方向设定)
1. .Start:子 View 居于 Row 开始绘制的边界(水平方向左对齐) 2. .End:子 View 居于 Row 结束绘制的边界(水平方向右对齐) 3. .Center:子 View 居于 Row 水平方向居中 4. .SpaceEvenly:子 View 平均分配 Row 水平方向(宽度) 5. .SpaceAround:子 View 平均分配 Row 水平方向(宽度),但是头部和尾部子 View 基于 Row 水平方向左边右边的边距是平分水平方向宽距的一半。 6. .SpaceBetween:子 View 平均分配 Row 水平方向(宽度),头部和底部子 View 贴着 Row 水平方向左侧和右侧,没有边距。

  • verticalAlignment(垂直方向设定)
  • .Top:子 View 居于 Row 垂直方向上方对齐
  • .Bottom:子 View 居于 Row 垂直方向下方对齐
  • .CenterVertically:子 View 居于 Row 垂直方向居中

Column / Row 设置 Weight 属性

设置 Weight 属性需要在 Column / Row 的子 View 中调用,使用 Modifie.weight()(与 LinearLayout 子 View 设置 weight 类似)。

属性介绍

kotlin @Stable fun Modifier.weight( weight: Float, fill: Boolean = true ): Modifier
- weight:设置当前子 ViewColumn / Row 内垂直方向 / 水平方向大小的权重 - fill:是否将分配的权重大小填充满,默认为 true

代码示例

kotlin @Composable fun ColumnView() { Column( modifier = Modifier .fillMaxSize() .background(Color.White) ) { Text( text = "竖向排列 0", Modifier .weight(1f) .background(Color.LightGray) ) Text( text = "竖向排列 1", Modifier .weight(0.5f) .background(Color.Cyan) ) Text(text = "竖向排列 2", Modifier.background(Color.Red)) Text(text = "竖向排列 3", Modifier.background(Color.Magenta)) } }

column_weight.png

Column / Row 添加滚动

添加滚动需要设置 Column / RowModifier.verticalScroll / Modifier.horizontalScroll

属性介绍

kotlin fun Modifier.verticalScroll( state: ScrollState, enabled: Boolean = true, flingBehavior: FlingBehavior? = null, reverseScrolling: Boolean = false )
- state:设置滚动位置和滚动位置监听 - enabled:是否开启滚动设置,默认开启(true) - flingBehavior:可自定义滑动速度 延时 等,默认是 DefaultFlingBehavior() 函数,在 androidx.compose.foundation.gestures.scrollable 下,实现了 ScrollScope.perFormFling 方法,可用于参考做自定义滑动属性。 - reverseScrolling:反向滑动

代码示例

kotlin @Composable fun ColumnScrollView() { val scrollLocation = rememberScrollState(300) //设置初始滑动位置 Log.i("====Column Scroll====", "Location:${scrollLocation.value}") Column( modifier = Modifier .height(200.dp) .fillMaxWidth() .background(Color.White) .verticalScroll(scrollLocation) ) { for (i in 0..20) { Text( text = "竖向排列 $i", modifier = Modifier.height(50.dp) ) } } }
column_scroll.gif

Box :(RelativeLayout)

### 属性介绍 kotlin @Composable inline fun Box( modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable BoxScope.() -> Unit )
- modifier:常用属性设定 - contentAlignment:子 View 位置设定 - propagateMinConstraintsBox 没有设置固定尺寸并且设置了最小尺寸,是否将最小尺寸值设置给子 View,默认为 false。 - content:添加布局内的 View

代码示例

kotlin @Composable fun BoxView() { Box( modifier = Modifier .fillMaxSize() .background(Color.White), contentAlignment = Alignment.Center ) { Text( text = "Text 1", modifier = Modifier .size(300.dp) .background(Color.Blue) ) Text( text = "Text 2", modifier = Modifier .size(200.dp) .background(Color.Red) ) Text( text = "Text 3", modifier = Modifier .size(100.dp) .background(Color.DarkGray) ) } }

image.png

BoxView 方向设定

Box 方向设定使用 Alignment 设定 - .TopStart:子 View 居于 Box 左上边界(左上角) - .TopCenter:子 View 居于 Box 上边界并且水平居中 - .TopEnd:子 View 居于 Box 右上边界(右上角)


  • .BootomStart:子 View 居于 Box 左和底部边界(左下角)
  • .BootomCenter:子 View 居于 Box 底部边界并且水平居中
  • .BootomEnd:子 View 居于 Box 右和底部边界(右下角)

  • .CenterStart:子 View 居于 Box 左侧并且垂直居中
  • .Center:子 View 居中
  • .CenterEnd:子 View 居于 Box 右侧并且垂直居中

BoxWithConstraints(子 View 可获取 Box 的约束属性)

View 可在 BoxWithConstraints 控件内获取到约束属性 ```kotlin @Composable fun BoxWithConstraintsView() { BoxWithConstraints( modifier = Modifier .fillMaxSize() .background(Color.White) ) { this.constraints this.maxHeight this.minHeight this.maxWidth this.minWidth

    Text(
        text = "Text 1",
        Modifier
            .width(this.minWidth)
            .height(this.minHeight)
    )
}

} ```

Compose 为什么没有 Margin 属性?

Android XML 开发中,经常用到 Margin(外边距)\ Padding(内边距)属性,但是在 Compose 中却发现只有 Modifier.padding(),这是因为 Modifier 有顺序调用的巧妙设计,下面举个栗子就明白了。
kotlin @Composable fun ColumnView() { Column( modifier = Modifier .fillMaxSize() .background(Color.White) ) { Text( modifier = Modifier .size(100.dp) .padding(start = 20.dp) .background(Color.Magenta), text = "Text 1" ) Text( modifier = Modifier .padding(start = 20.dp) .size(100.dp) .background(Color.Cyan), text = "Text 2" ) Text( modifier = Modifier .size(100.dp) .background(Color.LightGray) .padding(start = 20.dp), text = "Text 3" ) } }

compose_margin.png
- Text 1:设置宽高大小 -- 设置 padding -- 设置背景颜色,如图效果背景是在 padding 后绘制的。 - Text 2:设置 padding -- 设置宽高大小 -- 设置背景颜色,首先的 padding 设置和 XMLMargin 设定效果一样(设置外边距)。 - Text 3:设置宽高大小 -- 设置背景颜色 -- 设置 padding,设置内边距。

结尾

到此 Compose 布局控件 ColumnRowBox 介绍完毕,有哪里写错的地方欢迎大家留言指正。