Jetpack Compose之线性布局和帧布局

概述

Compose 中的线性布局对应的是Android传统视图中的LinearLayout,不一样的地方是,Compose根据Orientation的不同又将布局分为Column和Row, Column对应传统视图LinearLayout中orientation = “vertical”的情况,Row对应传统视图LinearLayout中orientation = “horizontal”的情况.由于两者内部元素在父容器中的布局和对其方式不同,分成两个组件有助于提供类型安全的Modifier修饰符。而Compose中的帧布局对应的是Android传统View中的FrameLayout,它可以让自己的子组件依次按照顺序推叠。

实例解析

1.线性布局

在Compose中,线性布局根据使用场景的不同,分为Column和Row,Column 是垂直线性布局组件,Row是水平线性布局组件

1.1 Column组件

@Composable
inline fun Column(
    modifier: Modifier = Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    content: @Composable ColumnScope.() -> Unit
)

上面是Column的参数列表,其中verticalArrangement和horizontalAlignment参数分别可以帮助我们安排子项的垂直/水平位置,在默认情况下,子项会以垂直方向靠上(Arrangment.Top)、水平方向靠左来布置子项的摆放

我们可以以一个例子看下Column的使用

@Composable
fun LinearLayoutDemo() {
    
    
    Column(
        modifier = Modifier
            .border(1.dp, color = Color.Red)
            .size(150.dp),
        verticalArrangement = Arrangement.Center
    ) {
    
    
        Text(
            text = "Hello World",
            style = MaterialTheme.typography.h6,
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
        Text(
            text = "JetPack",
            style = MaterialTheme.typography.h6,
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
        Text(
            text = "zhongxj",
            style = MaterialTheme.typography.h6,
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
    }
}

运行结果:
在这里插入图片描述

在上面的代码中,我们通过verticalArrangement参数,将Column中的Text摆放到了组件的中间,然后使用Modifier.align修饰符来独立设置子项的对齐规则
这里可能有人会问,不是有horizontalAlignment参数吗,水平方向为啥还要用Modifier.align呢?因为对于垂直布局中的子项,Modifier.align只能设置自己在水平方向的位置,反之水平布局的子项,只能设置自己在垂直方向的位置,就比如我们正在介绍的Column组件,当Column组件中有多个子项时,他们在垂直方向永远是线性排列的,如果允许子项被单独设置,就会出现不好的情况,比如Column中有A,B,C三项,如果配置A的对齐方向是Aligment.Bottom,B为Aligment.Top,这显然是无法实现的,所以Column的子项在垂直方向布局只能通过verticalArragnment进行整体设置。(注意:这里不是说Column只能使用verticalArragnment参数)

注意:在不给Column指定高度、宽度、大小的情况下,Column组件会默认包裹里面的子项,在这个时候我们是无法使用Column参数中的verticalArrangement或者horizontalAlignment来定位子项在Column中的整体位置的

1.2 Row组件

Row组件可以将内部子项按照从左到右的方向水平排列,和Cloumn组件配合使用就可以构建出很丰富美观的界面。下面是一个使用Row组件和Column组件制作的文章卡片,代码如下:

@Composable
fun ArticleCard() {
    
    
    Surface(
        shape = RoundedCornerShape(8.dp),
        modifier = Modifier
            .padding(horizontal = 12.dp)
            .fillMaxWidth(),
        elevation = 10.dp,
    ) {
    
    
        Surface(modifier = Modifier.padding(12.dp), color = Color(0xeeeeeeee)) {
    
    
            Column(modifier = Modifier.padding(12.dp)) {
    
    
                Text(
                    text = "JetPack Compose",
                    style = MaterialTheme.typography.h6
                )

                Spacer(modifier = Modifier.padding(vertical = 5.dp))
                Text(
                    text = " Jetpack Compose是第一个使用Kotlin正在开发中的大型项目," +
                            "因此Android团队正在探索Kotlin API指南的新世界,以创建一组特定于Compose API的指南," +
                            "该工作仍在进行中,仍然有很长的路要"
                )

                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
    
    
                    IconButton(onClick = {
    
     /*TODO*/ }) {
    
    
                        Icon(
                            imageVector = Icons.Filled.Favorite,
                            contentDescription = null, modifier = Modifier.size(16.dp)
                        )
                    }

                    IconButton(onClick = {
    
     /*TODO*/ }) {
    
    
                        Icon(
                            painterResource(id = R.drawable.comment),
                            contentDescription = null, modifier = Modifier.size(16.dp)
                        )
                    }

                    IconButton(onClick = {
    
     /*TODO*/ }) {
    
    
                        Icon(
                            painterResource(id = R.drawable.share),
                            contentDescription = null, modifier = Modifier.size(16.dp)
                        )
                    }
                }
            }
        }
    }
}

运行结果:
在这里插入图片描述

从上面的代码中可知,Row的horizontalArrangement参数帮助我们合理配置了按钮的水平位置。可以看到,图标部分,喜欢和分享按钮呈左右两端对齐,Arrangement定义了很多子项对齐的方式,除了Center(居中),Start(水平靠左),End(水平靠右)等常见的对齐方式,还有一些特定场景下的对齐方式,如Space Between,Space Evenly等。

2.帧布局

2.1 Box组件

Box组件是一个能够将里面的子项依次按照顺序堆叠的布局组件,在使用上类似于传统布局的FrameLayout,这个很简单,我们看下一段代码了解下它的使用。

@Composable
fun BoxDemo(){
    
    
    Box(modifier = Modifier
        .size(150.dp)
        .background(Color.Green))
    Box(modifier = Modifier
        .size(80.dp)
        .background(Color.Red))

    Text(text = "Hello World")
}

运行结果:
在这里插入图片描述

2.2 Surface组件

Surface从字面上理解是一个平面,在Material Design设计准则中也同样如此,我们可以将很多的组件摆放在这个平台之上,可以设置这个平面的边框,圆角,颜色等.例如,使用Surface实现一个卡片效果,代码如下:

@Composable
fun SurfaceDemo() {
    
    
    Surface(
        shape = RoundedCornerShape(8.dp),
        elevation = 10.dp,
        modifier = Modifier
            .width(300.dp)
            .height(100.dp),
        color = Color.Gray
    ) {
    
    
        Row(modifier = Modifier.clickable {
    
    }) {
    
    
            Image(
                painter = painterResource(id = R.drawable.portrait),
                contentDescription = null,
                modifier = Modifier.size(100.dp),
                contentScale = ContentScale.Crop
            )

            Spacer(modifier = Modifier.padding(horizontal = 12.dp))
            Column(
                modifier = Modifier.fillMaxHeight(),
                verticalArrangement = Arrangement.Center
            ) {
    
    
                Text(text = "zhongxj", style = MaterialTheme.typography.h6)
                Spacer(modifier = Modifier.padding(vertical = 8.dp))
                Text(text = "海塔灯")
            }
        }
    }
}

运行结果:
在这里插入图片描述

从上面的代码中我们可以看到,在Surface中我们主要编写UI代码,而Surface主要负责整个组件的形状,阴影,背景等,Surface可以帮助我们解耦一些代码,而不必在单个组件上添加很多的Modifier修饰符方法。

很多读者可能会有疑问有了Box为啥还要加一个Surface组件,其实Box和Surface组件还是有区别的,如果我们需要快速设置界面的形状,阴影,边框,颜色等,我们使用Surface会更好,因为这样可以减少Modifier的使用量。而如果我们只是需要简单设置界面背景颜色,大小,且需要简单布局下子项的位置,则可以使用Box

3.Spacer留白

在很多时候,我们需要让组件之间留有空白的间隙,这时候就可以使用Compose提供的Spacer组件,简单用一个demo展示Spacer的使用。

@Composable
fun SpacerDemo(){
    
    
   Row {
    
    
       Box(modifier = Modifier
           .size(100.dp)
           .background(Color.Green))
       Spacer(modifier = Modifier.width(20.dp))
       Box(modifier = Modifier
           .size(100.dp)
           .background(Color.Yellow))
       Spacer(modifier = Modifier.weight(1f))
       Box(modifier = Modifier
           .size(100.dp)
           .background(Color.Magenta))
   }
}

运行结果
在这里插入图片描述

从上面的代码中可以看出Spacer的另一种使用场景,那就是在代码中使用Box绘制占位的矩形块在没有内容的时候完成可以使用Spacer来替代。

总结

本文主要讲了线性布局和帧布局在Compose中如何使用,其实非常简单,就需要我们多加练习,没有啥技巧。等啥时候我们写Compose的UI和写XML的UI一样熟练的时候,我们的工作效率就会大大的提升,可以用更少的代码实现更炫的UI效果,而且Kotlin和Java还可以混合使用,现在我已经在用Compose写测试的界面了,非常方便,推荐读者也动起来,使用Java的小伙伴可以使用Compose写界面,Java写功能,而使用Kotlin的小伙伴,则可以更方便的使用Compose,一种语言,完成界面和功能,真的特别酷。

猜你喜欢

转载自blog.csdn.net/zxj2589/article/details/130241576