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,指定水平方向的对齐方式,有StartCenterHorizontallyEnd三种,默认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,指定垂直方向的对齐方式,有TopCenterVerticallyBottom三种,默认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)。这个属性我个人觉得使用频率不高,主要还是需要单独去指定各个子元素位置(使用Modifieralign方法)。

这里可以看个文档中的例子:

	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指定位置,通过sizepadding调整大小。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,它继承自BoxScopeBoxScope就是提供了上面使用到的alignmatchParentSize方法的作用域。

/**
 * 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
)

optimizationLevellayout_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. 参考

Compose 布局基础知识

Compose 的标准布局元素

到此这篇关于Jetpack Compose入门基础全面精讲的文章就介绍到这了,更多相关Jetpack Compose内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Jetpack Compose入门基础全面精讲的更多相关文章

  1. 一文详解 Compose Navigation 的实现原理

    这篇文章主要介绍了一文详解 Compose Navigation的实现原理,文章通告围绕主题展开详细的相关内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

  2. 使用Compose制作抖音快手视频进度条Loading动画效果

    这篇文章主要为大家介绍了使用Compose制作抖音快手视频进度条Loading动画效果,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. 利用Jetpack Compose实现绘制五角星效果

    这篇文章主要为大家介绍了Jetpack Compose如何使用自定义操作符实现绘制五角星效果,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下

  4. Android Jetpack 狠活Lifecycles与LiveData使用详解

    这篇文章主要为大家介绍了Android Jetpack 狠活Lifecycles与LiveData使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  5. Android开发Jetpack组件Lifecycle使用篇

    这一篇文章来介绍Android Jetpack架构组件的Lifecycle; Lifecycle用于帮助开发者管理Activity和Fragment 的生命周期, 由于Lifecycle是LiveData和ViewModel的基础;所以需要先学习它

  6. Android Compose自定义TextField实现自定义的输入框

    众所周知Compose中默认的TextField和OutlineTextField样式并不能满足所有的使用场景,所以自定义TextField就成了必备技能。本文将自定义TextField实现自定义的输入框,感兴趣的可以了解一下

  7. Android开发Compose remember原理解析

    这篇文章主要为大家介绍了Android开发Compose remember原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  8. koa中间件核心(koa-compose)源码解读分析

    这篇文章主要介绍了koa中间件核心(koa-compose)源码解读分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. Android Jetpack组件Navigation导航组件的基本使用

    本篇主要简单介绍了一下 Navigation 是什么 以及使用它的流程是什么,并且结合实际案例 操作了一番,Navigation 还有很多其他用法,如条件导航、嵌套图、过度动画 等等功能 有机会再操作,需要的朋友可以参考下

  10. Jetpack Compose Text的基本使用

    这篇文章主要介绍了Jetpack Compose Text的基本使用,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部