Android jetpack Compose之约束布局

news2024/11/27 14:47:52

概述

我们都知道ConstraintLayout在构建嵌套层级复杂的视图界面时可以有效降低视图树的高度,使视图树扁平化,约束布局在测量布局耗时上比传统的相对布局具有更好的性能,并且约束布局可以根据百分比自适应各种尺寸的终端设备。因为约束布局确实很好用,所以,官方也为我们将约束布局迁移到了Compose平台。本文就是介绍约束布局在Compose中的使用。

实例解析

在使用约束布局之前,我们需要先在项目中的app.gradle脚本中添加compose版本的ConstraintLayout依赖

implementation('androidx.constraintlayout:constraintlayout-compose:1.0.1')

引入依赖以后,我们就可以看下如何在Compose中使用约束布局了

1.创建引用

在传统View系统中,我们在布局XML文件中可以给View设置资源的ID,并将资源ID作为索引来声明对应组件的摆放位置。而在Compose的约束布局中,可以主动创建引用并绑定到某个具体组件上,从而实现与资源ID相似的功能,每个组件都可以利用其他组件的引用获取到其他组件的摆放位置信息,从而确定自己摆放位置。

Compose 创建约束布局的方式有两种,分别时createRef()和createRefs(),根据字面意思我们就可以很清楚的知道,createRef(),每次只会创建一个引用,而createRefs()每次可以创建多个引用(最多可以创建16个),创建引用的方式如下:

// 创建单个引用
 val text = createRef()
// 创建多个引用
 val (button1,button2,text) = createRefs()

2.绑定引用

当我们创建完引用后就可以使用Modifier.constrainAs()修饰符将我们创建的引用绑定到某个具体组件上,可以在contrainAs尾部Lambda内指定组件的约束信息。我们需要注意的是,我们只能在ConstraintLayout尾部的Lambda中使用createRefer,createRefs函数创建引用,并使用Modifier.constrainAs函数来绑定引用,因为ConstrainScope尾部的Lambda的Reciever是一个ConstraintLayoutScope作用域对象。我们可以先看下面一段代码了解下约束布局的引用绑定:

@Composable
fun ConstrainLayoutDemo()
{
    ConstraintLayout(modifier = Modifier
        .width(300.dp)
        .height(100.dp)
        .padding(5.dp)
        .border(5.dp, color = Color.Red)) {
        val portraitImageRef = remember {
            createRef()
        }

        Image(painter = painterResource(id = R.drawable.portrait)
            , contentDescription = null,
        modifier = Modifier.constrainAs(portraitImageRef){
            top.linkTo(parent.top)
            bottom.linkTo(parent.bottom)
            start.linkTo(parent.start)
        })

    }
}

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

上面的代码是实现一个用户卡片的部分代码,从代码中看到我们使用约束的时候需要用到Modifier.constrainsAs(){……}的方式。Modifier.constrainsAs的尾部Lambda是一个ConstrainScope作用域对象,可以在其中获取当前组件的parent,top,bottom,start,end等信息。并使用linkTo指定组件约束。在上面的界面中,我们希望用户的头像可以居左对齐,所以将top拉伸至父组件的顶部,bottom拉伸至父组件的底部,start拉伸至父组件的左边。我们再为卡片添加上用户的昵称和描述,全部代码如下所示:

@Composable
fun ConstrainLayoutDemo()
{
    ConstraintLayout(modifier = Modifier
        .width(300.dp)
        .height(100.dp)
        .padding(5.dp)
        .border(5.dp, color = Color.Red)) {
        val (portraitImageRef,usernameTextRef,descriptionTextRef) = remember {
            createRefs()
        }

        Image(painter = painterResource(id = R.drawable.portrait)
            , contentDescription = null,
        modifier = Modifier.constrainAs(portraitImageRef){
            top.linkTo(parent.top)
            bottom.linkTo(parent.bottom)
            start.linkTo(parent.start)
        })

        Text(text = "旅游小美女", fontSize = 16.sp, maxLines = 1,
        textAlign = TextAlign.Left,
        modifier = Modifier.constrainAs(usernameTextRef){
            top.linkTo(portraitImageRef.top)
            start.linkTo(portraitImageRef.end,10.dp)
        })

        Text(text = "个人描述。。。。。。。。", fontSize = 14.sp,
            color = Color.Gray,
            fontWeight = FontWeight.Light,
            modifier = Modifier.constrainAs(descriptionTextRef){
                top.linkTo(usernameTextRef.bottom,5.dp)
                start.linkTo(portraitImageRef.end,10.dp)
            }
        )
    }
}

运行结果:
在这里插入图片描述
在上面的代码中我们也可以在ConstrainScope中指定组件的宽高信息,在ConstrainScope中直接设置width与height的可选值如下所示:

在ConstrainScope中指定组件的宽高信息时,通过在Modifier.constrainAs(xxxRef){width = Dimension.可选值}来设置,可选值如下:
Dimension.wrapContent: 实际尺寸为根据内容自适应
Dimension.matchParent: 实际尺寸为铺满父组件的尺寸
Dimension,wrapContent: 实际尺寸为根据约束信息拉伸后的尺寸
Dimension.preferredWrapContent: 如果剩余空间大于更具内容自适应的尺寸时,实际尺寸为自适应的尺寸,如果剩余空间小于内容自适应尺寸时,实际尺寸为剩余空间尺寸
Dimension.ratio(String): 根据字符串计算实际尺寸所占比率:如1 :2
Dimension.percent(Float): 根据浮点数计算实际尺寸所占比率
Dimension.value(Dp): 将尺寸设置为固定值
Dimension.perferredValue(Dp): 如果剩余空间大于固定值时,实际尺寸为固定值,如果剩余空间小于固定值时,实际尺寸则为剩余空间尺寸

我们想象下,假如用户的昵称特别长,那么按照我们上面的代码展示则会出现展示不全的问题,所以我们可以通过设置end来指定组件所允许的最大宽度,并将width设置为preferredWrapContent,意思是当用户名很长时,实际的宽度会做自适应调整。我们将上面展示用户名的地方改一下,代码如下:

// 上面的代码只用改这个部分
   Text(
            text = "旅游小美女美美美美美名字很长长长长长长长长长",
            fontSize = 16.sp,
        textAlign = TextAlign.Left,
        modifier = Modifier.constrainAs(usernameTextRef){
            top.linkTo(portraitImageRef.top)
            start.linkTo(portraitImageRef.end,10.dp)
            end.linkTo(parent.end,10.dp)
            width = Dimension.preferredWrapContent
        })

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

辅助布局工具

在传统View的约束布局中有Barrier,GuideLine等辅助布局的工具,在Compose中也继承了这些特性,方便我们完成各种复杂场景的布局需求。

1.Barrier分界线

Barrier顾名思义就是一个屏障,使用它可以隔离UI布局上面的一些相互挤压的影响,举一个例子,比如我们希望两个输入框左对齐摆放,并且距离文本组件中的最长者仍保持着10dp的间隔,当用户名和密码等发生变化时,输入框的位置能够自适应调整。这里使用Barrier特性可以简单的实现这一需求:

@Composable
fun InputFieldLayout(){
    ConstraintLayout(
        modifier = Modifier
            .width(400.dp)
            .padding(10.dp)
    ) {
        val (usernameTextRef, passwordTextRef, usernameInputRef, passWordInputRef) = remember { createRefs() }
        val barrier = createEndBarrier(usernameTextRef, passwordTextRef)
        Text(
            text = "用户名",
            fontSize = 14.sp,
            textAlign = TextAlign.Left,
            modifier = Modifier
                .constrainAs(usernameTextRef) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                }
        )

        Text(
            text = "密码",
            fontSize = 14.sp,
            modifier = Modifier
                .constrainAs(passwordTextRef) {
                    top.linkTo(usernameTextRef.bottom, 20.dp)
                    start.linkTo(parent.start)
                }
        )
        OutlinedTextField(
            value = "",
            onValueChange = {},
            modifier = Modifier.constrainAs(usernameInputRef) {
                start.linkTo(barrier, 10.dp)
                top.linkTo(usernameTextRef.top)
                bottom.linkTo(usernameTextRef.bottom)
                height = Dimension.fillToConstraints
            }
        )
        OutlinedTextField(
            value = "",
            onValueChange = {},
            modifier = Modifier.constrainAs(passWordInputRef) {
                start.linkTo(barrier, 10.dp)
                top.linkTo(passwordTextRef.top)
                bottom.linkTo(passwordTextRef.bottom)
                height = Dimension.fillToConstraints
            }
        )
    }
}

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

2.Guideline引导线

Barrier分界线需要依赖其他引用,从而确定自身的位置,而使用Guideline不依赖任何引用,例如,我们希望将用户头像摆放在距离屏幕顶部2:8的高度位置,头像以上是用户背景,以下是用户信息,这样的需求就可以使用Guideline实现,代码如下:

@Composable
fun GuidelineDemo(){
   ConstraintLayout(modifier = Modifier
       .height(300.dp)
       .background(color = Color.Gray)) {
       val guideline = createGuidelineFromTop(0.2f)
       val (userPortraitBackgroundRef,userPortraitImgRef,welcomeRef) = remember {
           createRefs()
       }

       Box(modifier = Modifier
           .constrainAs(userPortraitBackgroundRef) {
               top.linkTo(parent.top)
               bottom.linkTo(guideline)
               height = Dimension.fillToConstraints
               width = Dimension.matchParent
           }
           .background(Color(0xFF673AB7)))

       Image(painter = painterResource(id = R.drawable.portrait),
           contentDescription = null,
           modifier = Modifier
               .constrainAs(userPortraitImgRef) {
                   top.linkTo(guideline)
                   bottom.linkTo(guideline)
                   start.linkTo(parent.start)
                   end.linkTo(parent.end)
               }
               .size(100.dp)
               .clip(CircleShape)
               .border(width = 2.dp, color = Color(0xFF96659E), shape = CircleShape))

       Text(text = "不喝奶茶的小白兔",
       color = Color.White,
       fontSize = 26.sp,
       modifier = Modifier.constrainAs(welcomeRef){
           top.linkTo(userPortraitImgRef.bottom,10.dp)
           start.linkTo(parent.start)
           end.linkTo(parent.end)
       })

   }
}

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

在上面的代码中,我们使用createGuidelineFromTop()方法创建了一条从顶部出发的引导线,然后用户背景就可以依赖这条引导线确定宽高了,然后对于头像,我们只需要将top和bottom连接至引导线即可

3.Chain链接约束

ContraintLayout的另一个好用的特性就是Chain链接约束,通过链接约束可以允许多个组件平均分配布局空间,类似于weight修饰符。例如我们要展示一首古诗,用Chain链接约束实现如下:

@Composable
fun showQuotesDemo() {
    ConstraintLayout(
        modifier = Modifier
            .size(400.dp)
            .background(Color.Black)
    ) {
        val (quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef) = remember {
            createRefs()
        }

        createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Spread
        )

        Text(text = "窗前明月光,",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesFirstLineRef) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "疑是地上霜。",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesSecondLineRef) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "举头望明月,",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesThirdLineRef) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "低头思故乡。",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesForthLineRef) {
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })
    }
}

运行结果:
在这里插入图片描述
如上面代码所示,我们要展示四句诗就需要创建四个引用对应四句诗,然后我们就可以创建一条垂直的链接约束将四句诗词连接起来,创建链接约束时末尾参数可以传一个ChainStyle,用来表示我们期望的布局样式,它的取值有三个,效果和意义如下所示:

(1)Spread:链条中的每个元素平分整个父空间

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Spread)

运行效果:

在这里插入图片描述

(2)SpreadInside:链条中的首尾元素紧贴边界,剩下的每个元素平分整个父空间

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.SpreadInside)

运行效果:

在这里插入图片描述

(3)Packed:链条中的所有元素都聚集到中间,效果如下

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Packed)

运行效果:

在这里插入图片描述

总结

关于Compose约束布局的内容就是这些了,本文主要是简单的介绍了Compose中约束布局的基本使用,要熟练掌握Compose约束布局,还需要读者多去联系,多使用约束布局写界面,这样就会熟能生巧,在此我只做一个抛砖引玉的活。有任何疑问,欢迎在评论区交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

simulink simscape传感总结

1. 传感模块概述2. 可观测的传感量3. 传感模块3.1 运动传感模块3.1.1 旋转和平移细分旋转平移 3.2 力传感模块3.2.1 关节力和力矩细分 1. 传感模块概述 Simscape提供传感模块,通过改变模型的输入和输出,可以进行许多分析,比如可以进行机械臂…

中移链控制台对接4A平台功能验证介绍

中移链控制台具备单独的注册登录页面,用户可通过页面注册或者用户管理功能模块进行添加用户,通过个人中心功能模块进行用户信息的修改和密码修改等操作,因业务要求,需要对中移链控制台的用户账号进行集中管理,统一由 4…

2 文件IO

2.1 文件描述符 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开 一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时, 用open或creat返回的文件描述符标识该文件&#xff0…

QT 网络编程之主机信息查询(QHostInfo 和 QNetworkInterface类)简介

Qt 网络模块提供了用于编写 TCP/IP 客户端和服务器端程序的各种类,如用于 TCP 通信的QTcpSocket 和 QTcpServer,用于 UDP 通信的 QUdpSocket,还有用于实现 HTTP、FTP 等普通网络协议的高级类如 QNetworkRequest,QNetworkReply 和Q…

【Redis】Redis中的5种基础数据类型详解

文章目录 1. Redis数据结构2. 基础数据结构详解2.1 String字符串2.2 List列表2.3 Set集合2.4 Hash散列2.5 Zset有序集合 1. Redis数据结构 对于Redis来说,所有的key(键)都是字符串,我们一般所讨论的Redis基础数据类型指的是存储的…

ref在Vue2、Vue3中的使用

文章目录 前言一、ref在Vue2中的用法二、ref在Vue3中的用法 前言 记录一下ref在Vue2与Vue3中的使用,ref可以获取DOM元素,也可以获取子组件的数据、方法。 一、ref在Vue2中的用法 给元素绑定一个ref,然后在js中通过this.$refs获取DOM。 ref命…

@PostConstruct注解和@PreDestroy注解

前言 Bean注解指定初始化和销毁的方法,也介绍了使用InitializingBean和DisposableBean来处理bean的初始化和销毁。JDK中还提供了两个注解能够在bean创建完成并且属性赋值完成之后执行一些初始化工作和在容器销毁bean之前通知我们进行一些清理工作。 1.PostConstru…

java 获取当前线程的方法

我们知道,线程是程序运行的基本单元,是程序中各进程之间通信的桥梁,一个线程的创建和销毁直接影响整个程序的运行效率。 我们在 Java中经常使用 Runnable接口来获取当前线程,获取线程的主要目的就是为了快速地启动进程。但是&…

一键导出ChatGPT聊天记录:让备份更简单

重要性: 备份ChatGPT的聊天记录同样非常重要,因为这些记录可能包含了您与ChatGPT的交互记录,这些记录可能包含了您的个人信息、兴趣爱好、偏好和其他敏感信息。以下是备份ChatGPT聊天记录的一些重要性: 防止数据丢失:…

FT2000+ qemu kvm 64C64G 通过频繁设置CPU online 状态导致虚拟机红旗操作系统假死测试用例

宿主机配置 虚拟机配置文件 <domain typekvm> //如果是Xen&#xff0c;则type‘xen’<name>redflag1</name> //虚拟机名称&#xff0c;同一物理机唯一<uuid>44748c15-7c00-4817-8724-675a27c3f821</uuid> //同一物理机唯一&#xff0c;可用uu…

北京 Meetup 预告 | 内含六个话题,满满干货,期待见面!

在春之末尾&#xff0c;夏之开始的5月&#xff0c;响应社区小伙伴们的呼唤&#xff0c;我们泽拓科技将在北京举办线下社区技术交流活动。 此次我们泽拓科技邀请了去哪儿网、ScaleFlux、美团、SphereEx的相关资深专家来分享他们的数据库探索与实践。我们真诚邀请数据库技术社区…

Day3_Springboot框架搭建

前面两天介绍了vue前端的主体框架&#xff0c;并完成了相关页面的部分设置&#xff0c;接下来开始介绍springboot后端开发的过程&#xff0c;手把手实践。包括项目的初始构建以及集成mybatis、mybatis-plus实现增删改查&#xff0c;分页查询&#xff0c;集成swagger-ui测试&…

Spring(4) Spring是如何使用三级缓存来解决循环依赖问题?

目录 1.什么是循环依赖&#xff1f;2.什么是Spring的循环依赖&#xff1f;3.三级缓存解决循环依赖3.1 假如只使用一级缓存3.2 假如使用二级缓存3.3 为什么要使用三级缓存 4.三级缓存解决循环依赖的局限性 1.什么是循环依赖&#xff1f; 假设我们有两个类 A 和 B&#xff0c;类…

【Docker】1、认识 Docker 和安装 Docker

目录 零、项目部署问题一、Docker 简介二、Docker 和虚拟机三、镜像和容器四、Docker 架构五、CentOS7 上安装 Docker(1) 卸载曾经安装过的 Docker(2) 安装 Docker(3) 启动 Docker(4) 启动、关闭、重启 Docker 六、配置 Docker 镜像国内仓库 零、项目部署问题 大型项目组件较多…

爬虫(requsets)笔记

1、request_基本使用 pip install requests -i https://pypi.douban.com/simple 一个类型六个属性 r.text 获取网站源码 r.encoding 访问或定制编码方式r.url 获取请求的urlr.content 响应的字节类型r.status_code 响应的状态码r.headers 响应的头信息 import requestsurl…

VS2022汇编环境搭建

VS2022汇编环境搭建 使用VS2022搭建汇编语言运行环境Step 1 安装VS2022Step 2 创建项目 使用VS2022搭建汇编语言运行环境 使用Visual Studio 2022 搭建汇编语言项目&#xff0c;运行汇编语言代码。 Step 1 安装VS2022 自行到官网下载安装&#xff0c;选择C编程环境。 Step…

【RabbitMQ】| Lion带你 (超详细) 从0到1使用SpringBoot操作RabbitMQ

目录 一. &#x1f981; 前言二. &#x1f981; SpringBoot操作RabbitMQⅠ. 前期准备工作1. 创建项目&#xff08;不细说&#xff09;2. 添加依赖3. 编写配置文件 Ⅱ. 创建队列和交换机Ⅲ. 创建生产者Ⅳ. 创建消费者 三. &#x1f981; 总结 一. &#x1f981; 前言 Spring Bo…

Spring MVC开发及使用(8000字详解)

如何学习 Spring MVC&#xff1f; 学习 SPring MVC 只需要掌握以下三个功能&#xff1a; 连接的功能&#xff1a;将用户&#xff08;浏览器&#xff09;和 Java 程序连接起来&#xff0c;也就是访问一个地址能够调用到我们 Spring程序&#xff1b;获取参数的功能&#xff1a;用…

颜色空间转换RGB-YCbCr

颜色空间 RGB、YUV和YCbCr都是人为规定的彩色模型或颜色空间&#xff08;有时也叫彩色系统或彩色空间&#xff09;。它的用途是在某些标准下用通常可接受的方式对彩色加以说明。本质上&#xff0c;彩色模型是坐标系统和子空间的阐述。 YCbCr与RGB的相互转换 RGB->YCbCr Y …

2023五一杯数学建模竞赛ABC题思路解析+代码+论文

AB题见文末&#xff0c;下面是C C题&#xff1a;“双碳”目标下低碳建筑研究 “双碳”即碳达峰与碳中和的简称&#xff0c;我国力争2030年前实现碳达峰&#xff0c;2060年前实现碳中和。“双碳”战略倡导绿色、环保、低碳的生活方式。我国加快降低碳排放步伐&#xff0c;大力推…