JetPack Compose之Modifier修饰符

前言

在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的,例如Button,TextField,TopAPPBar等。在布局上,Compose提供了Column,Row,Box三种布局组件,这些布局组件的使用类似于传统视图开发的LinearLayout(Vertical),LinearLayout(Horizontal),FrameLayout。而这些UI组件的使用都离不开一个重要的概念,那就是Modifier修饰符,它决定了UI组件的样式,比如背景,填充,布局等。

Modifier常用修饰符

Modifier.size

size修饰符用于设置被修饰组件的大小,使用如下所示:

@Composable
fun ShowCircleImg() {
    Row {
        Image(
            painterResource(id = R.drawable.portrait),
            contentDescription = null,
            modifier = Modifier
                .size(60.dp)
                .clip(
                    CircleShape
                )
        )

        Spacer(modifier = Modifier.width(10.dp))
        Image(
            painterResource(
                id = R.drawable.portrait
            ),
            contentDescription = null,
            modifier = Modifier
                .size(100.dp)
                .clip(CircleShape)
        )

        Spacer(modifier = Modifier.width(10.dp))
        // 使用size的重载方法单独设置组件的宽度和高度
        Image(
            painterResource(
                id = R.drawable.portrait
            ),
            contentDescription = null,
            modifier = Modifier.size(
                width = 200.dp,
                height = 500.dp
            )
        )
    }
}

在上面的代码中我们展示两个大小不一样的圆形图片,运行结果如下:

在这里插入图片描述
size提供重载方法,支持单独设置组件的宽度与高度

Modifier.background

background 修饰符用来为组件添加背景色,背景色支持设置Color的纯色背景,也可以使用brush设置渐变色背景。这里的Brush是Compose提供的用于创建线性变色的工具,如下面的代码所示:

@Composable
fun ShowModifierBG() {
    Row {
        Box(
            modifier = Modifier
                .size(200.dp)
                .background(color = Color.Red)
        ) {
            Text(text = "纯色", Modifier.align(Alignment.Center))
        }
        Spacer(modifier = Modifier.width(10.dp))

        Box(
            modifier = Modifier
                .size(200.dp)
                .background(brush = verticalGradient)
        ) {
            Text(text = "渐变色", Modifier.align(Alignment.Center))
        }

    }
}

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

注意:传统视图中View的background属性可以用来设置图片格式的背景,Compose的background修饰符只能设置颜色背景,图片背景需要使用Box布局配合Image组件实现。

Modifier.fillMaxSize

当我们想要组件的宽度或者是高度填满父容器空间时,我们可以使用Compose提供的fillMaxXXX系列方法
填满整个父容器空间的代码如下:

    Box(modifier = Modifier
         .fillMaxSize()
         .background(Color.Red))

高度填满父容器空间

    Box(modifier = Modifier
        .fillMaxHeight()
        .width(60.dp)
        .background(Color.Green))

宽度填满父容器空间

    Box(modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.Yellow))

Modifier.border和Modifier.padding

border修饰符用来为被修饰的组件添加边框,这个边框可以指定颜色,粗细,以及通过Shape指定形状,比如圆角矩形等。padding用来为被修饰的组件增加间隙。可以再border前后各插入一个padding,区分对外和对内的间距,代码如下:

@Composable
fun PaddingAndBorder() {
    Box(
        modifier = Modifier
            .padding(8.dp) // 外间隙
            .border(2.dp, Color.Red, shape = RoundedCornerShape(2.dp))
            .padding(8.dp) // 内间隙
    ) {
        Spacer(
            modifier = Modifier
                .size(width = 200.dp, height = 40.dp)
                .background(Color.Red)
        )
    }
}

运行的效果如下:
在这里插入图片描述

在这里插入图片描述
注意:在传统布局里面又Margin和padding之分,Compose中只有padding一种修饰符,根据在调用链中的位置不同而发挥不同的作用。

Modifier.offset

offset用来移动被修饰组件的位置,我们在使用的时候只分别传入水平方向和垂直方向的偏移量即可。代码如下:

@Composable
fun ModifierOffset() {
    Box(modifier =
        Modifier
            .size(300.dp)
            .offset(x = 30.dp, y = 75.dp)
            .background(Color.Red))
}

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

如上图所示,我们修改offset的值,图中红色方块的位置就会发生改变,读者可以运行到手机上后手动修改这个值,看手机上的界面变化。

注意:Modifier的调用顺序会影响最终UI呈现的效果,这里应该先使用offset修饰符偏移,再使用background修饰符绘制背景色

我们也可以使用offset的重载方法修改组件的位置,代码如下:

@Composable
fun ModifierCustomOffset() {
    Box(modifier =
    Modifier
        .size(300.dp)
        .offset { IntOffset(200.dp.roundToPx(), 150.dp.roundToPx()) }
        .background(Color.Red))
}

Modifier作用域限定修饰符

Compose 利用Kotlin的语法特性,让某些Modifier修饰符只能再特定的作用域中使用,这样有利于类型安全的调用他们,其实所谓的作用域,就是Kotlin中一个带有Receiver的代码块,例如Box组件参数的content就是一个Receiver类型为BoxScope的代码块,因此其子组件都处于BoxScope作用域中

@Composable
inline fun Box(
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    propagateMinConstraints: Boolean = false,
    content: @Composable BoxScope.() -> Unit
) {
   
}

Box{
// 该代码块Reciever即为BoxScope
}

不过我们需要注意的是,Reciever类型默认是可以跨层级访问的,例如下面的代码:

   class AScope {
        fun visitA() {}
    }

    class BScope {
        fun visitB() {}
    }

    fun funA(scope: AScope.() -> Unit) {
        scope(AScope())
    }

    fun funB(scope: BScope.() -> Unit) {
        scope(BScope())
    }

    fun main() {
        funA {
            funB {
                visitA()
            }
        }
    }

由于funB{…} 处于funA{…}内部,所以可以在funB{…}中访问属于funA{…}的方法visitA(),而在Compose的DSL中一般只需要调用当前作用域的方法,跨级访问会加大出错的概率,所以Compose提供了@LayoutScopemarker注解来规避Receiver的跨级访问。

@LayoutScopeMarker
@Immutable
interface BoxScope

我们常用的组件Receiveier作用域均已使用@LayoutScopemarker注解进行声明,添加了该组件的Receiver,我们在其作用域中默认只能调用作用域提供的方法。像跨级调用外层作用域的方法时,必须通过显示知名Receiver的类型。

作用域限定修饰符的好处在于类型安全,这在传统视图中是难以保证的,例如我们可以在布局的xml文件中为LinearLayout的子组件设置android:toRightOf属性,这设置对父布局没有任何意义,可能还会出错,但是我们很难做到根据不同夫类型安全地调用修饰符,而Compose的作用域限定符实现了Modifier的安全调用,我们只能在特定作用域中调用修饰符

matchParentSize

matchParentSize是只能在BoxScope中使用的作用域限定修饰符,当使用matchParentSize设置尺寸时,可以保证当前组件的尺寸与父组件相同。而父组件默认是wrapContent,这个属性会根据同级组件的尺寸来确定自身的尺寸,代码如下:
我们先定义一个简单的卡片子组件,用于展示效果:

@Composable
fun PhotoCard(modifier: Modifier = Modifier){
   Row(
       modifier = modifier
           .clip(RoundedCornerShape(4.dp))
           .background(MaterialTheme.colors.surface)
           .clickable {  }.padding(16.dp)

   ) {
       Surface(
           modifier = modifier.size(50.dp),
           shape = CircleShape,
           color = MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
       ) {
           Image(
               painter = painterResource(id = R.drawable.portrait),
               contentDescription = ""
           )
       }

       Column(
           modifier = modifier.padding(start = 8.dp).align(Alignment.CenterVertically)
       ) {
           Text(text="Zhongxj", fontWeight = FontWeight.Bold)
           Text(text = "3 分钟前", style = MaterialTheme.typography.body2)
       }
   }
}

然后使用matchParentSize修饰与卡片同级的BOX组件,为了演示,我特地在最外层组件上加了一个灰色背景和padding,不然直接就看不到效果了。

@Composable
fun MatchParentSizeDemo() {
    Box(
        modifier = Modifier
            .background(Color.Gray)
            .padding(10.dp)
    ) {
        Box(
            modifier = Modifier
                .matchParentSize()
                .background(Color.Red)
        )

        PhotoCard()
    }
}

代码运行结果如下:
在这里插入图片描述
这里的fillParentSize如果换成fillMaxSize,那么该组件的尺寸会被设置为父组件所允许的最大尺寸,这样会导致背景铺满整个屏幕

weight

在RowScope和ColumnScope中,可以使用专属的weight来设置尺寸,与size修饰符不同的是,weight修饰符允许组件通过百分比设置尺寸,也就是允许组件可以自适应适配各种屏幕尺寸的终端设备。
例如,我们希望绿色,红色,蓝色方块共享一整块column空间,其中每种颜色方块高度各占比1/3,代码如下:

@Composable
fun WeightModifierDemo() {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
    ) {
        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
                .background(Color.Green)
        ) {
            Text(text = "White", modifier = Modifier.align(Alignment.Center))
        }

        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
                .background(Color.Red)
        ) {
            Text(text = "Red", modifier = Modifier.align(Alignment.Center))
        }

        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
                .background(Color.Blue)
        ) {
            Text(text = "Blue", modifier = Modifier.align(Alignment.Center))
        }
    }

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

总结

本文关于Modifier修饰符就介绍到这里,是不是感觉Compose UI写起来特别爽,Modifier修饰符是特别重要的一个概念,建议读者应该在自己的电脑上手动敲下这些小例子,熟悉下Modifier的使用,这样在后面开发ComposeUI的时候才会事半功倍。有余力的读者也可以看下Modifier的实现原理,然后分享出来大家一起学习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IOC、AOP、和javca面试题

一、 1、控制反转(IOC) 将创建管理对象的工作交给容器来做。在容器初始化(或在某个时间节点)通过反射机制创建好对象,在使用时直接从容器中获取。 控制反转:将对象的控制权反过来交给容器管理。 IOC实现…

既然有http 请求,为什么还要用rpc调用?

先弄明白什么是RPC。 RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之…

【面试】Java并发编程面试题

文章目录基础知识为什么要使用并发编程多线程应用场景并发编程有什么缺点并发编程三个必要因素是什么?在 Java 程序中怎么保证多线程的运行安全?并行和并发有什么区别?什么是多线程多线程的好处多线程的劣势:线程和进程区别什么是…

基于java+ssm+vue病人跟踪治疗信息管理系统的搭建及源码

源码获取方式见文末 一.需求简介 病人治疗信息管理系统采用B/S模式,实现安全、快捷、高效的病人跟踪治疗信息管理。传统手工管理模式效率低下,已无法满足病人需求。 信息化时代的到来,使得开发病人跟踪治疗信息管理系统成为必然。 本系统采…

Linux 串口RS232/485/GPS 驱动实验(移植minicom)

目录Linux 下UART 驱动框架I.MX6U UART 驱动分析硬件原理图分析RS232 驱动编写移植minicomRS232 驱动测试RS232 连接设置minicom 设置RS232 收发测试RS485 测试RS485 连接设置RS485 收发测试GPS 测试GPS 连接设置GPS 数据接收测试串口是很常用的一个外设,在Linux 下…

python入门(一)conda的使用,创建修改删除虚拟环境,以及常用命令,配置镜像

文章目录背景1.conda的下载地址:2.安装3.执行常用命令1)查看版本2)查看所有虚拟环境3)创建虚拟环境4)激活虚拟环境5)关闭虚拟环境6)删除虚拟环境7)创建python2.7的虚拟环境8)使用pyt…

命令行上的数据科学第二版 二、开始

原文:https://datascienceatthecommandline.com/2e/chapter-2-getting-started.html 贡献者:Ting-xin 在这一章中,我需要确定你能够利用命令行做数据科学,为此你需要能满足一些条件。条件主要分为三个部分:&#xff08…

SQLyog图形化界面工具【超详细讲解】

目录 一、SQLyog 介绍 二、SQLyog 社区版下载 三、SQLyog 安装 1、选择Chinese后点击OK 2、点击“下一步” 3、选择“我接受”后点击“下一步” 4、点击“下一步” 5、修改安装位置(尽量不要安装在C盘),点击“安装” 6、安装后点击“…

剥茧抽丝,细数模块化的前世今生

写在前面 本篇是前端工程化打怪升级的第 1 篇,关注专栏 | 小册传送门 | 案例代码 近几年,时常会感叹,前端,发展的太迅猛了。日新月异的新概念,异彩纷呈的新思想泉水般涌出;前端项目的复杂度、开发成本、维护…

Python 自动化指南(繁琐工作自动化)第二版:十五、使用 PDF 和 WORD 文档

原文:https://automatetheboringstuff.com/2e/chapter15/ PDF 和 Word 文档是二进制文件,这使得它们比纯文本文件复杂得多。除了文本,它们还存储大量的字体、颜色和布局信息。如果您想让您的程序读写 PDF 或 Word 文档,您需要做的…

【从零开始学习 UVM】3.5、UVM TestBench架构 —— UVM Sequencer [uvm_sequencer]

文章目录 Usage(用法)Custom Sequencer(自定义sequencer)Class Hierarchy一个 sequencer 生成数据事务作为类对象并将其发送到driver以执行。建议扩展uvm_sequencer基类,因为它包含了允许sequence与driver通信所需的所有功能。基类是由可以被sequencer处理的requset和resp…

CookieSession

目录 一. 回顾cookie 二. 会话机制Session 1. cookie:标识用户的身份信息 2. cookie 和 session 的关联区别 三. 一些常用的核心方法及原理应用 1. HttpServletRequest 类中的相关方法 2. HttpServletResponse 类中的相关方法 3. HttpSession 类中的相关方…

博客2:YOLOv5车牌识别实战教程:理论基础

摘要:本篇博客介绍了YOLOv5车牌识别的理论基础,包括目标检测的概念、YOLO系列的发展历程、YOLOv5的网络结构和损失函数等。通过深入理解YOLOv5的原理,为后续实战应用打下坚实基础。 车牌识别视频正文: 2.1 目标检测概念 目标检测…

【01 Provider HAL and Device HAL】

1. Overview Camera Provider Hal 和 Camera Device Hal3 即在Hal3 整个架构中紫色框框出来的部分中: 2. 简介 (1). Android定义了几个Interface: ICameraProvider, ICameraDevice, ICameraDeviceSession, ICameraDeviceCallback 。 Camera Hal 层去实做了这些 Interface。…

chatGPT陪你读源码

概述 chatGPT从2022年11月份崭露头角以来,一直备受关注。他的人工智能对话颠覆了以往智能对话的刻板印象,跟chatGPT聊天,感觉就像百晓生一样,什么都懂。尤其在编程方面,chatGPT可以根据实际的业务场景需求&#xff0c…

GPT-4原论文详细解读(GPT-4 Technical Report)

GPT-4原论文详细解读(GPT-4 Technical Report)返回论文和资料目录 1.导读 相比之前的GPT-3.5等大型语言模型(这里可以看我的InstructGPT解读,也方便理解本文内容),GPT-4最大的不同在于变成了多模态&#…

部署大数据集群时踩过的坑 (持续更新)

大数据集群踩过的坑 前言(必看) 如果你遇到了和我一样的问题并通过搜索引擎进入这篇文章,请善用CtrlF键搜索 该自检手册仅用于自己学习使用,记录所有自己遇到的问题。如果你没有检索到你的问题,请使用Bing或Google进行搜索 该自检手册严格…

PCB生产工艺流程一:PCB分类的三大要点

PCB生产工艺流程一:PCB分类的三大要点 PCB在材料、层数、制程上的多样化以适不同的电子产品及其特殊需求。因此其种类划分比较多,以下就归纳一些通用的区别办法,来简单介绍PCB的分类以及它的制造工艺。那么我们就从它的三个方面来分析一下吧。 1、材料…

某汽车零部件企业:定期反钓鱼演练是降低企业安全风险的优选方案

客户背景 作为一家主要从事于汽车、摩托车零部件的开发、制造和销售的中日合资企业,服务的客户大多为国内汽车生产领域领先企业,旗下进出口业务较多,该汽车零部件企业需要与海外企业一直保持着电子邮件的往来,电子邮件安全十分重…

eNSP 实现VLAN间通信实验

关于本实验本实验将通过上述方法(配置Dot1q终结子接口和VLANIF接口)实现不同VLAN间的通信,其中涵盖了与这两种方法相关的原理、配置命令和验证方法。实验目的掌握配置Dot1q终结子接口的方法,实现VLAN间通信。掌握配置VLANIF接口的…