降Compose十八掌之『见龙在田』| Modifier

公众号「稀有猿诉」        原文链接 降Compose十八掌之『见龙在田』| Modifier

通过前面的文章我们学会了如何使用元素来构建和填充我们的UI页面,但这只完成了一半,元素还需要装饰,以及进行动画和事件响应,这才能生成完整的UI。这就要用到Modifier,Jetpack Compose中的灵魂,它被用来装饰和增强Composables,让一个个平凡的元素变成鲜活的,好看的,可交互UI。我们来具体的看一下Modifier的使用方法。

对于Compose来说,每一个元素叫做Composable,它是一个函数,比如前面学过的布局(如Row)和小部件(如Text)等都是一个Composable,可以把它理解成为一个元素。

概念和基本使用方法

Modifier之于元素,犹如CSS之于HTML,但能做的更多,因为除了样式装饰以外,Modifier还能做很多事情,比如响应用户输入。

每一个Composable都可以接收一个Modifier参数,准确地说第一个参数都是Modifier,可以把一个Modifier对象作为第一个参数传给元素;也可以用命名参数如modifier = Modifier.padding(8.dp)。Modifier支持链式调用,它的每个方法都会把当前对象返回:

@Composable
private fun Greeting(name: String) {Column(modifier = Modifier.padding(24.dp).fillMaxWidth()) {Text(text = "Hello,")Text(text = name)}
}

装饰元素的样式

重点来看一下如何用Modifier装饰元素的样式。需要注意的是Modifier是装饰元素的共性样式如尺寸,背景,边框和位移等等,而像具体元素特性,如Text中的文本样式,是无法用Modifier来修改的。

尺寸Size

尺寸对于一个UI元素来说是必要的,就是渲染之后的视觉上的宽度和高度。可以通过Modifier的下列函数来进行尺寸约束:

  • width/height - 指定固定的偏好宽度和偏好高度,参数传入具体的数值如Modifier.width(320.dp).height(480.dp),就是指定某个元素的宽度是320dp,高度是480dp。偏好(preferred)的意思是可能会被其他约束条件覆盖,而最终值可能会不一样。
  • size - 同时指定宽度和高度为某一偏好的数值,只传一个参数就是一个正方形,如Modifier.size(100.dp),等同于Modifier.width(100.dp).height(100.dp);传两个参数时分别指定宽和高,如Modifier.size(320.dp, 480.dp)等同于Modifier.width(320.dp).height(480.dp)。
  • wrapContentWidth/wrapContentHeight/wrapContentSize - 让元素自己决定尺寸,无视最小尺寸限制(minimum_wdith/minimum_height),类似于XML中的wrap_content,这是比较严格的限制。
  • requiredWidth/requiredHeight - 指定宽度和高度必须为某一数值,不可以被其他限制约束覆盖。带有In的函数可以指定一个范围。
  • requiredSize - 指定宽度和高度必须为某一数值,带有In的函数可以指定范围。
  • widthIn/heightIn/sizeIn - 带有in的函数,可以指定一个范围而非具体数值,比如Modifier.widthIn(10.dp, 100.dp),就是说限制此元素的宽度为10dp到100dp之间。
  • fillMaxWidth/fillMaxHeight - 不固定具体的数值,按比例填充最大可用空间,比例为1.0时填满,类似于XML中的match_parent。
  • fillMaxSize - 按比例填充满可用空间。
  • weight - 权重比例,仅在父布局是Row或者Column时,且尺寸与父布局约束一致时有效,比如在Row中,对width生效,在Column中对height生效。最终的占比是『权重比例 x 可用空间』,不指定weight则weight是0,比如一个Row中,有三个元素,其中两个元素A和B指定了weight为1和2,另一个没指定,那么A将占Row中剩余可用宽度的1/3,B将占2/3。与View中的LinearLayout中的权重是差不多的。

Modifier修饰尺寸的函数比较多,容易学杂了,需要梳理一下:size相当于快捷方式,可以同时约束宽和高;带有In的函数可以为某个约束指定范围。宽高是一种限制性约束,不同的函数的限制严格性是不一样的,带有required是最严格的限制约束,优先级最高,如有冲突,以它为准;wrapContentWidth/wrapContentHeight/wrapContentSize是较严格的限制,仅次于required;width/height/size是中等严格,较wrapContent再次之;weight再次之;fillMax则是最弱的限制。

间隔

间隔(padding)是在元素与其边界之间添加的额外的空白空间,Modifier.padding不影响元素的尺寸,它是在测量之前就应用生效。

对于有XML经验的同学来说,以往的间隔有两个,一个是margin控制着元素边界之外的间隔,padding控制着边界与元素本身内容间隔。对于Modifier来说,只有一个函数,在不同的位置调用padding函数会有不同的效果,如果在尺寸之后调用padding,则是调整边界与内容之间的间隔,如果是在尺寸之前调用,则是调整边界与外部的间隔。另外,就是padding不可以传负值。

@Composable
fun PaddingDemo(modifier: Modifier = Modifier.fillMaxSize()) {Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {Text(text = "降龙十八掌",style = MaterialTheme.typography.headlineLarge,modifier = Modifier.padding(16.dp) // As margin: outside space beyond border.background(Color.Cyan).size(360.dp, 120.dp).padding(10.dp) // As padding: space between border and content)}
}

padding_demo.png

位移Offset

函数Modifier.offset用来给水平和垂直方向加一个位移,数值可正可负,注意仅是增加位移,并不会改变元素的尺寸。与View中的translateX和translateY是类似的。它有两个函数,只有一个参数时是水平和垂直方向都加上相同的位移;两个参数时是分别指定水平方向和垂直方向。

@Composable
fun ModifierDemo(modifier: Modifier = Modifier.fillMaxSize()) {var offset by remember { mutableStateOf(0) }Column(modifier = modifier.padding(8.dp).clickable { offset += 8 }) {Text(text = "降龙十八掌",style = MaterialTheme.typography.headlineLarge,color = MaterialTheme.colorScheme.primary,modifier = Modifier.offset(offset.dp, offset.dp).background(Color.Cyan).padding(16.dp))}
}

offset_demo.gif

因为offset并不改变元素的尺寸,仅是在原位置上进行偏移,所以多用于点击效果,或者点击动画。

背景Background

使用Modifier.background函数来修改元素的背景颜色,唯一需要注意的是padding的影响,background是给尺寸所指定的区域加背景色,所以padding调用的位置会有影响。

边框Border

用Modifier.bodrer函数可以指定边框的样式,如形状,粗细,线条和颜色。需要注意的是它也是跟尺寸一样的,受padding的影响:

@Composable
fun BorderWithShape(modifier: Modifier = Modifier.fillMaxSize()) {Box {Text(text = "降龙十八掌",style = MaterialTheme.typography.headlineLarge,modifier = Modifier.padding(10.dp).border(2.dp, SolidColor(Color.Green), RoundedCornerShape(20.dp)).padding(10.dp))}
}

border_demo.png

变幻

Modifier还能对元素进行一些变幻,如透明度(Alpha),旋转(Rotate)和缩放(Scale)。通常用来实现一些非动画的静态特效。

Modifier.alpha指定透明度,0是透明,1是完全不透明,默认值是1.0。

Modifier.rotate实现旋转,参数是一个角度,顺时针旋转为正值,逆时针旋转为负值,默认值是0度。

Modifier.scale是以元素的几何中心为中心点进行缩放负值会进行水平和垂直方向翻转:

@Composable
fun TransformationDemo(modifier: Modifier = Modifier.fillMaxSize()) {Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {Text(text = "降龙十八掌",style = MaterialTheme.typography.headlineLarge,color = MaterialTheme.colorScheme.primary,modifier = Modifier.padding(16.dp).alpha(0.618f).rotate(11.8f).scale(0.618f).background(Color.Cyan).size(360.dp, 120.dp).offset(10.dp, 10.dp))}
}

transformation_demo.png

事件监听

Modifier.clickable函数用来指定点击事件响应。此外,还可以用于指定元素是否可以点击。

另外,还可以通过Modifier.scrollable来指定元素是否可以滑动。

最佳实践

Modifier是非常强大的,也是非常复杂的,前面列出的都是最为常用的一些函数。接下再来学习一下使用Modifier时需要注意的事项。

顺序很重要

Modifier有很多很多函数,修改着同一个对象实例,有些函数会相互影响,因此这些函数的调用顺序就变得相当重要,特别是涉及尺寸强相关的装饰特性时,如background和border,它们会受到padding以及变幻的影响。比如前面变幻小节的例子,可以试着修改函数的调用顺序,就会发现结果会不一样。在实例使用时,如果出现与预期不一致的结果时,就尝试调整一下Modifiier函数的顺序,看是否是顺序 导致的。

留意上下文

在Compose中,有一些Modifier函数只能在特定的元素中使用,这就涉及了Compose上下文(Scope)。比如说像Modifier.align只能在BoxScope中使用,也就是说只能在Box的子元素中使用。对其他任何布局来说都是不能用的,所以在使用的时候也要注意元素所在的父布局。

尽可能的复用

每个元素在渲染的时候都需要一个Modifier对象,通常情况下都是通过Modifier的函数进行对象创建。但对于一些循环的场景,且Modifier对象没啥变化 时,这时就应该复用对象,而非每次都创建。比如说动画,以及像集合性布局的子布局,这时都应该在其父布局缓存Modifier对象,直接传给子元素,而不是让其每次都创建新对象:

val modifier = Modifier.padding(12.dp).background(Color.Gray)
@Composable
fun LoadingWheelAnimation() {val animatedState = animateFloatAsState(/*...*/)LoadingWheel(// 把Modifier对象缓存到上一级的父布局中,以免每帧动画都创建一个Modifier对象modifier = reusableModifier,animatedState = animatedState)
}

对于集合性布局也最好是能复用Modifier对象:

val reusableItemModifier = Modifier.padding(bottom = 12.dp).size(216.dp).clip(CircleShape)@Composable
private fun AuthorList(authors: List<Author>) {LazyColumn {items(authors) {AsyncImage(// 提升到上一级中时进行缓存,而不是每次都创建modifier = reusableItemModifier,)}}
}

保持一致性

一致性对于代码的可维护性和可扩展性是非常重要的,因为每个元素都需要Modifier对象,在Compose中到处都可以看到Modifier,在实际使用中保持一致性就非常重要。比如说Modifier要作为Composable的第一个参数,参数的命名应该是modifier,并且最好要有默认值,可以查阅Compose本身的代码,可以发现其所有的元素都遵循此约定。另外,就是对于共性的装饰要提升到父布局中进行统一设定,比如说根布局统一设定padding,而不是每个子布局进行分别设定,等等。

参考资料

  • Compose modifiers
  • 6. Jetpack Compose Modifiers
  • 6. Using Compose Modifiers

subscription

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

保护原创,请勿转载!

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

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

相关文章

洛谷 数学进制 7.9

P1100 高低位交换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码一 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)const ll N1e510; char a[N];int main() {IOS;ll a;int b[32]…

关于Qt模型插入最后一行数据中存在未填满的项,点击导致崩溃的解决办法

在使用Qt模型视图框架的时候&#xff0c;你可能会遇见这种情况&#xff1a;给QTableView设置设置模型的时候&#xff0c;网模型里面插入数据&#xff0c;因为数据是一行一行插入的&#xff0c;即要使用model的appandRow函数&#xff0c;但有时候最后一行数据没有填满一行&#…

Java面试八股之MySQL索引B+树、全文索引、哈希索引

MySQL索引B树、全文索引、哈希索引 注意&#xff1a;B树中B不是代表二叉树&#xff08;binary&#xff09;&#xff0c;而是代表平衡&#xff08;balance&#xff09;&#xff0c;因为B树是从最早的平衡二叉树演化而来&#xff0c;但是B树不是一个二叉树。 B树的高度一般在2~…

新火种AI|OpenAI的CEO又有新动作?这次他成立了AI健康公司

作者&#xff1a;一号 编辑&#xff1a;美美 AI技术即将改变医疗健康市场。 就在前两天&#xff0c;人工智能和医疗健康领域迎来了一个重要时刻。OpenAI的CEO萨姆阿尔特曼&#xff08;Sam Altman&#xff09;与Thrive Global的CEO阿里安娜赫芬顿&#xff08;Arianna Huffing…

业务咨询方案 + IT落地方案建议设计

近期&#xff0c;在深入探索咨询方案的实施与落地路径时&#xff0c;体会到了一系列心得与启示&#xff0c;旨在为未来的项目实践提供可借鉴的蓝本。 咨询方案的精髓&#xff0c;在于“业务引领&#xff0c;IT支撑”的核心理念。所以方案的前提是在于业务的梳理&#xff1b; …

已解决 javax.xml.transform.TransformerFactoryConfigurationError 异常的正确解决方法,亲测有效!!!

已解决 javax.xml.transform.TransformerFactoryConfigurationError 异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 一、问题分析 二、报错原因 三、解决思路 四、解决方法 五、总结 博主v&#xff1a;XiaoMing_Java 博主v&#x…

淮北在选择SCADA系统时,哪些因素会影响其稳定性?

关键字:LP-SCADA系统, 传感器可视化, 设备可视化, 独立SPC系统, 智能仪表系统,SPC可视化,独立SPC系统 在选择SCADA系统时&#xff0c;稳定性是一个关键因素&#xff0c;因为它直接影响到生产过程的连续性和安全性。以下是一些影响SCADA系统稳定性的因素&#xff1a; 硬件质量…

百度文心4.0 Turbo开放,领跑国内AI大模型赛道!

百度文心4.0 Turbo开放&#xff0c;领跑国内AI大模型赛道&#xff01; 前言 文心一言大模型 就在7月5日&#xff0c;在2024世界人工智能大会 (WAIC) 上&#xff0c;百度副总裁谢广军宣布文心大模型4.0 Turbo正式向企业客户全面开放&#xff01;这一举动直接引发了业界的关注。那…

【C++知识点总结全系列 (08)】:面向对象编程OOP

这里写目录标题 1、OOP概述(1)面向对象四大特征A.抽象B.封装C.继承D.多态 (2)构造函数A.What&#xff08;什么是构造函数&#xff09;B.Why&#xff08;构造函数的作用&#xff09;C. Which&#xff08;有哪些构造函数&#xff09; (3)析构函数A.What&#xff08;什么是析构函数…

【JS|第21期】JavaScript模块化:深入解析三种文件暴露方式

日期:2024年7月6日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.4083…

全志A527 T527 android13支持usb摄像头

1.前言 我们发现usb摄像头在A527 android13上面并不能正常使用,需要支持相关的摄像头。 2.系统节点查看 我们查看系统是否有相关的节点生成,发现/dev/video相关的节点已经生成了。并没有问题,拔插正常。 3.这里我们需要查看系统层是否支持相关的相机, 我们使用命令进行…

【INTEL(ALTERA)】为什么我使用 PIO 边缘捕获中断的 Nios® II 设计不能正常工作?

目录 说明 解决方法 说明 当用户选择了不正确的边缘捕获设置&#xff0c;从而阻止触发中断时&#xff0c;可能会出现此问题。 在 PIO&#xff08;并行 I/O&#xff09;英特尔 FPGA IP内核中&#xff0c;如果“启用单个位设置/清除”选项被关闭&#xff0c;则将任何值写入边…

vue实例和容器的一夫一制——04

//准备容器 <div classapp> <h1>{{mag}}</h1> </div> //准备容器 <div classapp> <h1>{{mag}}</h1> </div> //准备容器 <div classapp2> <h1>{{name}}</h1> </div> <script> // 验…

基于Java+SpringMvc+Vue技术的药品进销存仓库管理系统设计与实现系统(论文7000字参考+源码+LW+部署讲解)

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

Java虚拟机面试题汇总

目录 1. JVM的主要组成部分及其作用&#xff1f; 1.1 运行时数据区划分&#xff1f; 1.2 哪些区域可能会发生OOM&#xff1f; 1.3 堆和栈的区别&#xff1f; 1.4 内存模型中的happen-before是什么&#xff1f; 2. HotSpot虚拟机对象创建流程&#xff1f; 2.1 类加载过程…

7.9总结

容易推出当移动i与j时等价于j-i-1个左右交换&#xff0c;且每次交换逆序数的奇偶改变&#xff08;无相同元素&#xff09;&#xff0c;假设有一个状态c&#xff0c;且a与b必须以等量的左右交换转移为c&#xff0c;则必须数量相同&#xff0c;元素相同&#xff08;使用异或解决&…

tomcat 项目迁移,无法将项目作为服务service启动

背景 测试服务器需要迁移到正式服务器上&#xff0c;为了方便省事&#xff0c;将测试服务器上的一些文件直接复制到正式服务器 问题 使用startup启动项目之后&#xff0c;可以直接使用使用tomcat9w启动&#xff0c;或者作为服务service启动的时候&#xff0c;显示无法访问到资源…

欧拉部署nginx

1.下载nginx 下载地址&#xff1a;https://nginx.org/en/download.html 选择稳定版本 下的镜像文件进行下载 2.解压Nginx包 cd /root/nginx tar -zxvf nginx-1.26.0.tar.gz cd nginx-1.26.03.安装nginx相关依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl o…

机场公厕厕位指引屏,布线简单,安装便捷

在人潮涌动的机场&#xff0c;公厕不仅是旅客的必需设施&#xff0c;更是衡量机场服务质量的重要指标。然而&#xff0c;传统机场公厕往往存在信息不透明、清洁维护滞后、高峰期拥挤等问题&#xff0c;严重影响了旅客的使用体验。近年来&#xff0c;随着智慧机场理念的兴起&…

Linux 网络--TCP协议收包流程(NAPI机制)

Linux 网络--TCP协议收包流程&#xff08;NAPI机制&#xff09; 平台环境简介&#xff1a;宿主机: ubuntu18.04Linux内核源码版本: Linux-4.15网卡驱动: Intel e1000 &#xff08;ubuntu 虚拟机默认网卡驱动&#xff09;协议&#xff1a;TCP协议&#xff0c;本文分析收包过程 本…