Jetpack Compose入门基础全面精讲
作者:唯鹿
1. Column
子元素按竖直顺序排列,相当于竖直方向的LinearLayout
。
@Composable inline fun Column( modifier: Modifier = Modifier, verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, content: @Composable ColumnScope.() -> Unit )
modifier
是修饰符,我们放到下一篇详细说明。verticalArrangement
,指定子元素在Column
中的排列方式,默认是Top。下图是文档给的各属性示意,很直观。
horizontalAlignment
,指定水平方向的对齐方式,有Start
、CenterHorizontally
,End
三种,默认Start
。这部分和我们的android:gravity
属性类似,这里是通过两个属性分开配置。content
,就是我们的子元素,用大括号包住。
@Composable fun ArtistCard() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
2. Row
子元素按水平顺序排列,相当于水平方向的LinearLayout
。基本用法与Column
一致,简单说明一下。
@Composable inline fun Row( modifier: Modifier = Modifier, horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, verticalAlignment: Alignment.Vertical = Alignment.Top, content: @Composable RowScope.() -> Unit )
horizontalArrangement
,指定子元素在水平方向的排列方式,默认是Start
。直接上图:
verticalAlignment
,指定垂直方向的对齐方式,有Top
、CenterVertically
,Bottom
三种,默认Top
。
3. Box
box就像盒子一样,里面的东西可以层层摆放。大体相当于FrameLayout
。
@Composable inline fun Box( modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable BoxScope.() -> Unit )
contentAlignment
,指定子元素的对齐方式,八个方向加一个正中九种位置,默认是左上角(LTR)。这个属性我个人觉得使用频率不高,主要还是需要单独去指定各个子元素位置(使用Modifier
的align
方法)。
这里可以看个文档中的例子:
Box { Box(Modifier.fillMaxSize().background(Color.Cyan)) Box( Modifier.matchParentSize() .padding(top = 20.dp, bottom = 20.dp) .background(Color.Yellow) ) Box( Modifier.matchParentSize() .padding(40.dp) .background(Color.Magenta) ) Box( Modifier.align(Alignment.Center) .size(300.dp, 300.dp) .background(Color.Green) ) Box( Modifier.align(Alignment.TopStart) .size(150.dp, 150.dp) .background(Color.Red) ) Box( Modifier.align(Alignment.BottomEnd) .size(150.dp, 150.dp) .background(Color.Blue) ) }
预览效果:
Box中的各个子Box从底部向上叠加。通过align
指定位置,通过size
、padding
调整大小。matchParentSize
类似match_parent
属性,宽高填充满父布局。
注意:这个子元素的Box和父元素Box虽然长得一样,但实际不是一个组件。前者类似于View,不能添加子View,可以指定大小样式,而后者类似ViewGroup。
propagateMinConstraints
,子元素是否使用指定的最小约束,默认false。这个属性直接这么解释很抽象,我们可以接着用上面的例子,添加下面的代码:
Box( Modifier.sizeIn(100.dp, 200.dp), propagateMinConstraints = true ) { ... }
我们指定子元素最小宽是100dp,高是200dp后,预览效果如下:
可以看到原本的红蓝色块因为高度只有150dp,所以被约束为了最小的200dp,变成的长方形。
4. BoxWithConstraints
BoxWithConstraints
和上面的Box
很相似,唯一不同是它多了约束。我们先看源码:
@Composable fun BoxWithConstraints( modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.TopStart, propagateMinConstraints: Boolean = false, content: @Composable BoxWithConstraintsScope.() -> Unit )
注意到不同处是BoxWithConstraintsScope
,它继承自BoxScope
。BoxScope
就是提供了上面使用到的align
和matchParentSize
方法的作用域。
/** * Receiver scope being used by the children parameter of [BoxWithConstraints] */ @Stable interface BoxWithConstraintsScope : BoxScope { /** * The constraints given by the parent layout in pixels. * * Use [minWidth], [maxWidth], [minHeight] or [maxHeight] if you need value in [Dp]. */ val constraints: Constraints /** * The minimum width in [Dp]. * * @see constraints for the values in pixels. */ val minWidth: Dp /** * The maximum width in [Dp]. * * @see constraints for the values in pixels. */ val maxWidth: Dp /** * The minimum height in [Dp]. * * @see constraints for the values in pixels. */ val minHeight: Dp /** * The maximum height in [Dp]. * * @see constraints for the values in pixels. */ val maxHeight: Dp }
所以BoxWithConstraints
不同就是在Box
的基础上多了最大最小宽度高度的属性。可以用它来做一些页面适配之类的工作,使用例子如下:
BoxWithConstraints { if (maxWidth < 400.dp) { Column { Image(/* ... */) Title(/* ... */) } } else { Row { Column { Title(/* ... */) Description(/* ... */) } Image(/* ... */) } } }
5. ConstraintLayout
使用 Android View 系统时,在嵌套某些 View(如 RelativeLayout)时,可能会出现一些性能问题。由于 Compose 可以避免多次测量,因此可以根据需要进行深层次嵌套,而不会影响性能。
虽然不用考虑嵌套带来的性能问题,但是这写起来一层套一层的也挺闹心的。加上ConstraintLayout
我个人已经非常习惯使用了,所以也很希望在Compose中也能使用到它。个人感觉ConstraintLayout
可以提高可读性。
使用Compose中的ConstraintLayout
需要额外添加依赖:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-rc02"
@Composable inline fun ConstraintLayout( modifier: Modifier = Modifier, optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD, crossinline content: @Composable ConstraintLayoutScope.() -> Unit )
optimizationLevel
和layout_optimizationLevel
一样,用来约束优化的。默认OPTIMIZATION_STANDARD
,只优化直接约束和barrier
约束。通常我们不需要修改它。
这里用官方的一个例子简单说明一下它的使用方法:
ConstraintLayout( modifier = Modifier .fillMaxSize() ) { val (image, header, tag1, tag2, tag3, bSignup, bLogin, disclaimer) = createRefs() val g1 = createGuidelineFromStart(44.dp) val g2 = createGuidelineFromEnd(44.dp) Image( modifier = Modifier.constrainAs(image) { width = Dimension.value(201.dp) height = Dimension.value(179.dp) top.linkTo(parent.top, 32.dp) start.linkTo(g1) }, painter = painterResource(id = R.drawable.intercom_snooze), contentDescription = null ) Text( modifier = Modifier.constrainAs(header) { top.linkTo(image.bottom, 32.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h5, ) Text( modifier = Modifier.constrainAs(tag1) { top.linkTo(header.bottom, 16.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, text = stringResource(id = R.string.welcome_tagline1) ) Text( modifier = Modifier.constrainAs(tag2) { top.linkTo(tag1.bottom, 8.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, text = stringResource(id = R.string.welcome_tagline2) ) Text( modifier = Modifier.constrainAs(tag3) { top.linkTo(tag2.bottom, 8.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, text = stringResource(id = R.string.welcome_tagline3) ) Button( modifier = Modifier.constrainAs(bSignup) { bottom.linkTo(bLogin.top, 16.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, onClick = {} ) { Text(text = stringResource(id = R.string.sign_up)) } Button( modifier = Modifier.constrainAs(bLogin) { bottom.linkTo(disclaimer.top, 16.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, onClick = {}, ) { Text(text = stringResource(id = R.string.log_in)) } Text( modifier = Modifier.constrainAs(disclaimer) { bottom.linkTo(parent.bottom, 8.dp) start.linkTo(g1) end.linkTo(g2) width = Dimension.fillToConstraints }, text = stringResource(id = R.string.trial_disclaimer), style = MaterialTheme.typography.caption, ) }
预览效果如下(包括约束效果):
说明一下代码中的属性和方法:
createRefs()
是创建引用。或者说定义需要使用的id。Modifier.constrainAs
是定义约束条件。括号内填写开始创建的引用。类似android:id="@+id/xxx"
。createGuidelineFromXXX
就是创建一个Guideline
,例子中创建了左右两个Guideline
作为左右两边间距参考线。linkTo
是用来指定约束条件的。例如top.linkTo(image.bottom, 32.dp)
相当于app:layout_constraintTop_toBottomOf="@+id/image"
加android:layout_marginTop="32dp"
。Dimension.fillToConstraints
,填充满约束,类似宽高指定0dp。
当然还有许多的属性方法没有用到,也就不详细的介绍了,有兴趣的可以看官方demo。
到此,基础布局篇结束,下一篇详细介绍 Modifier
修饰符。
6. 参考
到此这篇关于Jetpack Compose入门基础全面精讲的文章就介绍到这了,更多相关Jetpack Compose内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!