Android的Compose

Jetpack Compose 是用于构建原生 Android 界面的新工具包,无需修改任何 XML 布局,也不需要使用布局编辑器。相反,只需调用可组合函数来定义所需的元素,Compose 编译器即会完成后面的所有工作。

简而言之,使用Compose,不再需要xml编写页面。


可组合函数(Composable function)

Compose是围绕可组合函数构建的,只需要描述应用界面的外观并提供数据依赖,而不必关注界面的构建过程(如初始化元素、将其附加到父项等)。而创建Composable function,只需要添加注解@Composable到函数名称前。

首先,我们构建创建一个应用:ComposeTutorial。在AS中选择Empty Activity创建。

添加文本元素

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {//在此处定义布局
            //此处的Text方法是由Compose界面库定义的文本Composable function
            Text("Hello world!")
        }
    }
}

setContent块定义了activity的布局,在此处我们添加了Text即“Hello World!”。

自定义可组合函数

如果需要将一个函数转换为Composable function,我们需要添加注解“@Composable”。

修改MainActivity:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")//使用我们自定义的Composable function
        }
    }
}

@Composable//添加注解,使该函数成为Composable function
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

在AS中预览Composable function

借助@Preview注解,可以在AS中预览Composable function,无需安装到设备或虚拟器中。

唯一要求是该注解不能用于接收参数的函数中,因此在MainActivity新增如下函数:

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}

在重新构建后,该函数没有被调用,应用本身不会改变,但是AS对于所有添加了@Preview注解的界面元素可以进行预览,点击如下两个按钮之一即可:


布局(Layout)

在此处我们实现一个简单的聊天界面,显示发送者和消息内容,点击消息时可缩放。

添加多个文本

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            //向Composable function中传入发送者名称和消息内容 
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

//新建一个Message类,包含消息发送者和消息内容
data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

这段代码会在内容视图中创建两个文本元素。不过,由于未提供有关如何排列这两个文本元素的信息,因此它们会相互重叠,使文本无法阅读。

使用Column、Row、Box

Column,直译为“圆柱体、长列”。

使用该函数修改MessageCard,可以垂直排列元素,使其不再重叠文本。

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

同样的,可以使用Row函数水平排列元素,而使用Box函数可以堆叠元素。

添加图片元素

使用Resource Manager从照片库中导入图片,修改MessageCard:

@Composable
fun MessageCard(msg: Message) {
    //使用Row方法,水平排列图片和消息
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
        Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}

配置布局(Modifier)

使用修饰符(Modifier)实现。

Compose中的每一个组件都具有Modifier属性,通过他我们可以设置组件的大小、间距、外观,甚至添加互动事件,如点击、触摸事件。

@Composable
fun MessageCard(msg: Message) {
    //在消息周围添加8dp的距离
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                //设置图片大小
                .size(40.dp)
                //将图片修剪为圆形
                .clip(CircleShape)
        )

        //在图片和消息之间添加一个水平的空间(Spacer),间距为8dp
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // 在发送者和消息内容之间添加一个垂直的空间
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}

Material Design

Compose 旨在支持 Material Design 原则。它的许多界面元素都原生支持 Material Design。

使用

Jetpack Compose 原生提供 Material Design 3 及其界面元素的实现。我们使用 Material Design 样式改进MessageCard可组合项的外观。

在创建ComposeTutorial项目时,会同时创建一个名为“ComposeTutorialTheme”的Material主题,和一个来自Material Design 3的“Surface”。我们将用到这两位来封装MessageCard函数。

Material Design是围绕Color、Typography、Shape来构建的,我们将逐一添加这些元素。

修改MainActivity:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            //使用ComposeTutorialTheme和Surface封装MessageCard函数
            ComposeTutorialTheme {
                //将给定的组件或布局填满父容器的界面
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    //在@Preview中也要封装,沿用应用主题中定义的样式,保持统一
    ComposeTutorialTheme {
        Surface {
            MessageCard(
                msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
            )
        }
    }
}
  

颜色

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               //为图像增加一个圆框
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               //通过MaterialTheme.colorScheme,使用已封装主题中的颜色设置样式
               color = MaterialTheme.colorScheme.secondary
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

Typography(排版)

MaterialTheme 中提供了 Material Typography 样式,只需将其添加到 Text 可组合项中即可。

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.bodyMedium
           )
       }
   }
}

Shape(形状)

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           //将消息详情封装在Surface中,此时可自定义消息详情的大小、形状等布局
           Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.bodyMedium
               )
           }
       }
   }
}

启用深色主题

又称夜间模式。由于支持Material Design,Jetpack Compose默认能够处理深色主题。

使用Material Design颜色、文本和背景时,系统会自动适应深色背景。

//可以在文件中以单独函数的形式创建多个预览,也可以向同一个函数中添加多个注解
@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}


列表和动画

创建消息列表(LazyColumn、LazyRow)

LazyColumn、LazyRow是Compose常见的两个组件,他们的优点是可以延迟加载。他们只会加载当前可见的列表项,并在滚动时动态回收其他项,这使得他们适用于展示大量数据或无限滚动的列表。

在使用中,会包含一个items子项。他接受LIst作为参数,并且其lambda会接收到参数。系统会针对提供的List的每个项调用此lambda。

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        //items子项
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

在展开消息时显示动画效果

为了存储某条消息是否已展开,我们使用remember和mutableStateOf函数。

可组合函数可以使用remember将本地状态存储到内存中,并跟踪传递给mutableStateOf的值的变化。而mutableStateOf函数可以在可组合函数内部创建一个可变的状态,并将其与UI组件进行绑定。当状态值发生变化时,Compose会自动重绘相关的组件。

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // 在此变量中,跟踪当前消息是否展开
        var isExpanded by remember { mutableStateOf(false) }

        // 当点击该消息时,改变展开状态
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // 若展开,全部显示;不展开,最大显示一行
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

注:需要添加以下导入内容才能正确使用 Kotlin 的委托属性语法(by 关键字):
import androidx.compose.runtime.getValue

import androidx.compose.runtime.setValue

使用by关键字是避免每次都访问value属性的好方法。

同时需要注意的是,我们应该只在可组合函数的作用域之外改变状态。这是因为可组合项可以频繁运行、且以任何顺序执行。​​​​​​​此处我们可以在clickable中修改isExpanded的值,是因为clickable不是可组合函数。

除了remember关键字,我们还可以使用rememberSaveable,它与前者类似,但存储的值可以在重新创建activity和进程后保存下来。需要注意的是,rememberSaveable适用于UI状态,如购物车的商品数量或选定的标签页,但不适用于过渡动画状态等。

同时我们可以加入颜色,在消息缩放时改变消息的颜色。但不能只是简单的改变消息的背景颜色,我们应当加入动画,使得变化时逐步更改。

相同的,在点击缩放时,我们也可以加上动画,使得缩放更加顺滑。

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        var isExpanded by remember { mutableStateOf(false) }
        // 该变量会逐步更新颜色,animateColorAsState函数实现颜色之间的过渡动画效果
        val surfaceColor by animateColorAsState(
            if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
        )

        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
                color = surfaceColor,
                //加入animateContentSize,给缩放加入动画,更加顺滑
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

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

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

相关文章

【论文精读】ESViT

摘要 基于transformer的SSL方法在ImageNet线性检测任务上取得了最先进的性能&#xff0c;其关键原因在于使用了基于对比学习方法训练单尺度Transformer架构。尽管其简单有效&#xff0c;但现有的基于transformer的SSL&#xff08;自监督学习&#xff09;方法需要大量的计算资源…

Laravel02 路由基本概念和用法 给视图传递请求参数

Laravel02 路由基本概念和用法 1. 路由的基本概念2. 给视图传递请求参数 1. 路由的基本概念 routes文件夹下的web.php是用来定义路由规则的。 自己定义一个路径 2. 给视图传递请求参数 在laravel里使用一个辅助函数request来快速获取请求参数

[ansible] playbook角色

一、roles Roles又称为角色&#xff0c;playbook被称为剧本。Roles角色是自1.2版本之后引入的新特性&#xff0c;用于层次性、结构化的组织剧本 roles能够根据层次型结构自动装载变量文件、任务集、以及触发的动作等&#xff0c;要使用roles只需要在剧本中使用include命令引入…

五种多目标优化算法(MOAHA、MOGWO、NSWOA、MOPSO、NSGA2)性能对比,包含6种评价指标,9个测试函数(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOAHA 1.2MOGWO 1.3NSWOA 1.4MOPSO 1.5NSGA2 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数&#xff08;zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3&#xff09;&#xff…

计算机网络看这里就够了!!!

入门概念 参考视频链接&#xff1a; 1.2 因特网概述_哔哩哔哩_bilibili 一些基础概念 因特网发展阶段&#xff1a; 三个大标题&#xff1a; 从单个ARPANET-----逐步建成三级结构的因特网----逐步形成多层次ISP结构(互联网服务提供商&#xff08;Internet Service Provider…

MAC端Terminus 绿色版下载【一键安装,即可使用】

Termius Mac 是一款非常好用而且漂亮的SSH客户端&#xff0c;能快速远程控制服务器 现在呢&#xff0c;很多小伙伴&#xff0c;都开始使用这个软件啦 但是对于mac系统来说&#xff1a; 这个软件不要在苹果app store下载&#xff0c;不能实现传输功能这个软件目前有7天适用期&a…

【Linux权限】 Linux权限管理 | 粘滞位

文章目录 Linux权限管理什么是权限 ❓&#x1f4a6; 文件访问者的分类(人)&#x1f4a6; 文件类型和访问权限(事物属性) &#x1f4a6; 文件访问权限的相关设置方法目录的权限 粘滞位 Linux权限管理 什么是权限 ❓ 权限本质上是决定某件事情&#xff0c;某人能否做。 Linux下…

【Linux】主机搭建 Linux服务器环境 笔记

目录 前言选择系统软件1. 用U盘装系统2. 安装 Centos7.93. 网络套件 应用软件1. ngnix2. 防火墙配置3. nodejs 后记 前言 过年买了个 mini 主机当玩具玩一下&#xff0c;这里记录下。 选择 已有主力机 (windows) 的情况下&#xff0c;使用过如下四种 Linux宿主环境。这里总…

猫头虎分享已解决Bug || Python AI错误处理:IndexError

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

基于情感分析的网上图书推荐系统

项目&#xff1a;基于情感分析的网上图书推荐系统 摘 要 基于网络爬虫的数据可视化服务系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取网上商品评论信息实现商品评论的情感分析系统功能。对于…

IO进程-day3

1>多线程实现文件拷问 代码&#xff1a; #define MAXSIZE 1024 #include<myhead.h>int main(int argc, char const *argv[]) {FILE *srcfpNULL;FILE *destfpNULL;if((srcfp fopen("./pm.bmp", "r")) NULL){perror("fopen error");re…

【PCIE709-F】基于复旦微JFM7VX690T80 FPGA的全国产化8通道光纤双FMC接口数据处理平台

板卡概述 PCIE709-F是一款基于上海复旦微电子的28nm 7系列FPGA JFM7VX690T80的全国产化8通道光纤双FMC接口数据预处理平台&#xff0c;该板卡采用复旦微的高性能7系列FPGA作为实时处理器&#xff0c;实现4路10G SFP光纤以及1路QSFP通信接口、实现1路X8 PCIE数据传输的功能。板载…

MySQL 锁的内存结构

目录 1.摘要 2. 加锁的本质 3. 锁结构详解 3.1 锁所在的事务信息 3.2 索引信息 3.3 表锁/行锁信息 3.4 type_mode 3.5 其他信息 3.6 一堆比特位 1.摘要 在 MySQL 中&#xff0c;有很多种锁&#xff0c;例如行锁&#xff0c;表锁&#xff0c;页锁&#xff0c;全局锁&a…

0207-2-计算机组成

Principle-of-Computer-Composition 计算机组成原理思维导图 计算机组成 第一章 计算机系统概论 冯诺依曼型计算机特点 1.计算机由运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入和输出设备5部分组成2.采用存储程序的方式&#xff0c;程序和数据放在同一个存…

网页布局之浮动

一&#xff0c;传统网页布局的三种方式 普通流&#xff08;标准流&#xff09;、浮动、定位。 二&#xff0c;标准流&#xff08;普通流/文档流&#xff09; 即为标签按照规定好的默认方式排列。 1.块级元素会独占一行&#xff0c;从上向下顺序排列。 常用元素&#xff1a;…

3ds Max视频怎么渲染 3ds Max云渲染操作

在3ds Max软件中制作视频动画本质上是逐帧生成画面&#xff0c;并将这些连续帧串联起来创造出动态连贯的视觉效果。常见的视频帧率包括25 FPS(每秒帧数)、60 FPS、以及120 FPS等&#xff0c;帧率的提升可以使视频动画更加流畅。在实质上&#xff0c;视频渲染就是动画渲染&#…

大厂的数据质量中心系统设计

日常工作中&#xff0c;数据开发上线完一个任务后并不是就可以高枕无忧&#xff0c;时常因上游链路数据异常或者自身处理逻辑的 BUG 导致产出的数据结果不可信。而问题发现可经历较长周期&#xff08;尤其离线场景&#xff09;&#xff0c;往往是业务方通过上层数据报表发现数据…

[计算机网络]---UDP协议

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、端口号…

[职场] 质量管理涉及哪些方面 #职场发展#笔记#经验分享

质量管理涉及哪些方面 质量管理是一种管理方法和理念&#xff0c;旨在确保产品、服务或流程符合预期的质量标准和要求。它涉及制定质量政策和目标、制定质量计划、执行质量控制措施、进行质量评估和持续改进等活动。 质量管理员是负责管理和维护质量管理体系的专业人员。他们负…

Spring6学习技术|IoC+基于xml管理bean

学习材料 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09; IoC 控制反转。是一种设计思想。 1.获取bean对象的方法 通过id&#xff0c;通过class&#xff0c;和双重方式。 ApplicationContext context new Cla…