Android Jetpack Compose——一个简单的聊天界面

news2024/10/7 14:22:34

Jetpack Compose——聊天界面

  • 前言
  • 效果视频
  • 引入
    • Row
    • Column
    • Text
    • Image
  • 聊天界面
    • 效果
    • 左边布局
  • 右边布局
  • 插入数据
  • 总结

前言

目前声明式UI已经成为前端开发趋势,除了一开始的跨端开发React,Flutter等以及Web支持外,后续Android和IOS平台也相继推出声明式开发,Android通过Jetpack Compose配合Kotlin强大的语言特性进行开发,彻底摆脱啦命令式使用XML文件进行UI布局

效果视频

Android Jetpack ——一个简单的聊天界面

引入

在进行代码解析之前,先介绍几个常见的布局

Row

类似于Android中LinearLayout的horizontal排列方式,与Flutter的Row一致。
Modifier基本执行了一个组件大部分配置工作,内部实现了一些列扩展函数并通过then函数实现链式调用,verticalAlignment属性为竖向对齐方式,horizontalArrangement为横向对齐方式

Row(
        modifier = Modifier.padding(all = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Start
        )  {
         //some sub views
        }

Column

Column和Row除了排列方式不一样,其余都大致差不多,类似于LinearLayout的vertical排列方式

Column(
            modifier = Modifier.weight(1f),
            horizontalAlignment = Alignment.End
        ){
         //some sub views
        }

Text

文本框,类似Android的TextViewtext属性为文本内容,color属性为文本颜色,style属性为文本样式,可以设置文本大小、是否加粗、样式等,系统内置了很多样式,textAlign属性为文本对齐方式

Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.bodySmall,
                textAlign = TextAlign.Right
            )

Image

等同于Android的ImageView,painter通过painterResource可以直接配置图片地址(drawable),通过modifier属性我们可以直接修改图片的是否圆角、边框、大小等属性,就不需要专门去建立一个xml文件去配置

Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)
                .clickable { CircleShape }
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )

聊天界面

通过LazyColumn实现了一个竖向列表,数据为固定数据,根据下标分别位于左右俩端布局位置,然后默认文字显示一行,通过点击该行文字之后,文字内容进行展开,并改变其背景颜色,此Demo改编自官方

效果

左边布局

添加@Composable注解,才能使用声明式UI,声明式UI采用的都是树形结构,以此例,Row为该树根节点,拥有俩个子节点,分别为ImageColumn(中间那个空间占位符省略),然后Column又拥有俩个子节点,分别为SurfaceText,其中Surface又拥有一个Text子节点。

监听某行是否被点击,然后执行背景修改主要通过如下,就是相当于观察者模式,监听isExpanded字段,然后发生改变,就立即通过观察者类似。官方解释如下:

重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
//监听isExpanded字段
var isExpanded by remember { mutableStateOf(false) }

//收缩和扩展对应俩种颜色,由isExpanded字段决定
        val surfaceColor by animateColorAsState(
            targetValue = if (isExpanded)
                Color.Cyan
            else
                MaterialTheme.colorScheme.surface
        )

最后在需要添加点击方法的组件中添加 modifier = Modifier .clickable { isExpanded = !isExpanded }即可,每一次点击都改变其值,然后获取该值的节点进行重绘,更新

@Composable
fun MessageLeft(msg : Message){
    Row(
        modifier = Modifier.padding(all = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Start) {
        //图像
        Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)//图像大小
                .clip(CircleShape)
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )

        //左右间隔
        Spacer(modifier = Modifier.width(10.dp))

        //重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
        // 该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
        //通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
        var isExpanded by remember { mutableStateOf(false) }

        val surfaceColor by animateColorAsState(
            targetValue = if (isExpanded)
                Color.Cyan
            else
                MaterialTheme.colorScheme.surface
        )

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

            //上下间隔
            Spacer(modifier = Modifier.height(10.dp))

            Surface(
                shape = RectangleShape,
                shadowElevation = 1.dp,
                tonalElevation = 1.dp,
                color = surfaceColor,
                modifier = Modifier
                    .animateContentSize()
                    .padding(1.dp)
            ) {
                Text(
                    text = msg.content,
                    modifier = Modifier
                        .clickable { isExpanded = !isExpanded }
                        .padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium,
                    overflow = TextOverflow.Ellipsis
                )
            }

        }
    }
}

右边布局

右边与左边差不多,不同点在于改变了horizontalArrangement排列方式,使其呈右边排列,然后给文字添加了一个权重属性 modifier = Modifier.weight(1f),,防止该行内容过多,将右边图像挤到屏幕之外

@Composable
fun MessageRight(msg: Message){
    Row(
        modifier = Modifier
            .padding(10.dp)
            .fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End) {
        //给左边文字一个权重,避免文字过多,让右边图像无法显示
        Column(
            modifier = Modifier.weight(1f),
            horizontalAlignment = Alignment.End
        ) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.bodySmall,
                textAlign = TextAlign.Right
            )

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

            var isExpanded by remember { mutableStateOf(false) }
            val surfaceColor by animateColorAsState(
                targetValue = if (isExpanded)
                    Color.Green
                else
                    MaterialTheme.colorScheme.surface
            )

            Surface(
                shape = RectangleShape,
                shadowElevation = 1.dp,
                tonalElevation = 1.dp,
                color = surfaceColor,
                modifier = Modifier
                    .animateContentSize()
                    .padding(1.dp)
            ) {
                Text(
                    text = msg.content,
                    modifier = Modifier
                        .clickable { isExpanded = !isExpanded }
                        .padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium,
                    overflow = TextOverflow.Ellipsis

                )
            }
        }
        Spacer(modifier = Modifier.width(10.dp))
        Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)
                .clickable { CircleShape }
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )
    }
}

插入数据

等同于Android XML的RecyclerView,是不是很简单,不需要写Adapter和子项XMl文件以及一大堆接口什么的啦

@Composable
fun ShowMessage(msgList: List<Message>){
    //竖向列表
    LazyColumn{
        itemsIndexed(items = msgList){
            index, item ->
            if (index %2 == 0)
                MessageLeft(msg = item)
            else
                MessageRight(msg = item)
        }
    }
}

总结

Jetpack Compose 声明式UI一开始用起来可能不太习惯,但是适应之后,直接起飞,大大提高开发效率,减少开发时间,而且大部分前端都使用声明式UI,想要兼修,就不必费很大功夫,就例如Flutter,从UI而言俩个基本都差不多,只不过Flutter通过Widget进行嵌套,分为WidgetElementRenderObject三个部分,通过runtimetypekey判断此节点是否修改,从而判断是否需要进行重绘。
最后建议诸位Android开发者用起来,Android Jetpack Compose已经差不多出来有一年时间啦,逐渐稳定

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

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

相关文章

零基础快速开发Vue图书管理系统—登录注册篇(一)

零基础快速开发Vue图书管理系统—登录注册篇&#xff08;一&#xff09; 一、图书管理系统项目功能 二、项目技术选型 前端主要采用&#xff1a;Vue3.x (vuex/vue-router)、Ant Design Vue、Axios等服务端主要采用&#xff1a;Node.js、Koa、Mongoose等数据库主要采用&#x…

Docker安装Redis集群失败经历汇总

在程序员的开发过程中&#xff0c;Redis可以说基本上是必不可少的缓存中间件。不管是二进制包还是docker安装Redis的文章在网上都是数不胜数。我之前自己玩Redis的时候基本不是二进制包安装就是docker安装&#xff0c;也没有尝试过集群方式。每次需要的时候&#xff0c;网上百度…

DataFrame转化为json的方法教程

网络上有好多的教程&#xff0c;讲得不太清楚和明白&#xff0c;我用实际的例子说明了一下内容&#xff0c;附档代码&#xff0c;方便理解和使用 DataFrame.to_json(path_or_bufNone, orientNone, date_formatNone, double_precision10, force_asciiTrue, date_unitms, defau…

考研数据结构大题整合_组一(ZYL组)

考研数据结构大题整合 目录考研数据结构大题整合一、ZYL组ZYL组一ZYL组二ZYL组三ZYL组四ZYL组五ZYL组六ZYL组七ZYL组八一、ZYL组 ZYL组一 1.一棵树有度为i的结点ni 个(i1,2,3,…m), 求叶结点的个数.&#xff08;10分&#xff09; 2、已知带权连通图G(V,E)的邻接表如图所示&am…

rubbitmq 图形界面使用 常用六种通信模式 Simple-Work-fanout-direct-topic-headers

阿里云服务器添加rubbitmq需要开启端口:rabbitmq阿里云服务器开放端口号 Rubbitmq地址: 服务器地址:15672 1.简单模式Simple 一个生产者、一个消费者&#xff0c;不需要设置交换机&#xff08;使用默认的交换机&#xff09; 2.工作队列模式Work Queue 一个生产者、多个消费者&a…

windows操作系统双网卡问题处理办法

windows操作系统双网卡问题处理办法&#xff08;详解&#xff09;一、命令说明二、处理办法1.设置外网网关为默认网关2.查看当前路由表3.删除缺省路由4.添加访问外网的缺省路由5.添加访问内网的路由信息一、命令说明 显示 IP 路由表的信息 route print显示 IP 路由表中以 192…

3.7.3、ARP协议(网际层)

地址解析协议 ARP 1、工作原理 在共享总线型的以太网中 为了简单起见&#xff1a;只有各主机所配置的 IP 地址和其网卡上固化的 MAC 地址 假设主机 B 要给主机 C 发送数据包 主机 B 知道主机 C 的 IP 地址&#xff0c;但是不知道 C 的 MAC 地址 因此&#xff0c;主机 B 的…

使用 Bytebase 管理 Rainbond 上的应用数据库

在应用的发布过程中数据库的结构变更一直是最复杂也是风险最大的环节&#xff0c;而 Bytebase 可以对这一过程进行全生命周期的管理。在 Rainbond 中安装 Bytebase&#xff0c;轻松管理部署在 Rainbond 上的所有数据库。 Bytebase 是什么&#xff1f; Bytebase 是一个开源的数…

linux驱动 usb转串口ch344 改变读取缓冲区大小

开发环境 核心板&#xff1a;IMX6 内核版本&#xff1a;linux4.1.5 问题 通过USB扩展出来的串口接收数据会出现截断现象&#xff0c;而且每次截断的大小都一样。而核心板提供的串口UART就没有这个现象。 核心板自带串口正常的现象&#xff1a; 扩展串口异常现象&#xff1a…

【软件测试】8年资深测试说出来我们的心声......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 执着于手动的功能测…

VLAN划分-----计算机网络

拓扑图 LSW1与LSW2都是三层交换机&#xff0c;现在两台交换机分别连着两台pc。 其中&#xff1a; LSW1的0/0/1端口连着pc1&#xff0c;0/0/2连着pc2&#xff0c;0/0/3端口连着lsw2。 LSW2的0/0/1端口连着pc3&#xff0c;0/0/2连着pc4&#xff0c;0/0/3端口连着lsw1。 不同vlan…

pycharm opencv无法自动补全

我的环境 python 3.6.9opencv-python 4.4.0.42opencv-contrib-python 4.6.66ubuntu 18.04 LTSpycharm 2020.3.2 解决方案 首先找到cv2的site-packagespip3 show opencv-python进入到该目录, 复制so结尾文件至上级目录: cp cv2.cpython-36m-x86_64-linux-gnu.so ../等待pych…

基于粒子群算法和遗传算法优化的高速列车横向悬挂

目录 前言 1.高速列车模型 2.优化算法优化模糊PID流程 3.普通PID、优化算法模糊PID仿真对比 3.1 模糊控制器设计 3.2 仿真结果 3.2.1粒子群优化PID 3.2.2粒子群优化模糊PID 3.2.3遗传算法优化模糊PID 4.总结 前言 高速列车&#xff0c;是指最高行驶速度在200km/h 及以…

二、【React-Router5】路由的基本使用

文章目录1、写在前面的总结2、效果图3、项目结构4、CODE4.1、index.js4.2、App.js4.3、About.jsx4.4、Home.jsx5、Result6、路由组件与一般组件7、Link 升级 NavLink8、封装NavLink8.1、MyNavLink.jsx8.2、修改上面4.2部分代码1、写在前面的总结 明确好界面中的导航区、展示区…

火山引擎数智平台:CDP产品要能与多方联动

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 CDP&#xff08;Customer Data Platform&#xff0c;客户数据平台&#xff09;市场将迎来新一轮的高速增长。 国际数据公司&#xff08;以下简称“IDC”&#xff0…

[附源码]Python计算机毕业设计SSM流浪猫狗救助站(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

ofxTimeMeasurements——OpenFrameworks插件,可以轻松测量C++代码任何部分的执行时间

一、简介 ofxTimeMeasurements是一款用于OpenFrameworks 开源C框架的插件&#xff0c;可以让使用者轻松测量C代码任何部分的执行时间。其优势在于以图形化的方式显示代码执行时间。效果如下&#xff1a; 只是它必须依赖OpenFrameworks&#xff0c;所以如果你不用这个框架&…

《Head First HTML5 javascript》第10章 自定义对象

2022.11.23 第10章 自定义对象 面向对象OOP(Object Oriented Programming) 对象是一个包含相关数据和方法的集合&#xff08;通常由一些变量和函数组成&#xff0c;我们称之为对象里面的属性和方法&#xff09;对象是存储在单个分组中的相关功能的集合。在 JavaScript 中&…

第二证券|多只公募基金损失惨重;储能板块低开高走

今天早盘&#xff0c;A股大幅低开&#xff0c;上证50指数直接跳空跌破2500点&#xff0c;最多跌逾3%&#xff0c;创业板指亦跌破2300点整数关口。 盘面上&#xff0c;酒店餐饮、旅游、储能、ST等板块逆势活跃&#xff0c;酿酒、工程机械、互联网、证券等板块跌幅居前。北上资金…

【LeetCode每日一题:1758. 生成交替二进制字符串的最少操作数~~~模拟+遍历+计数】

题目描述 给你一个仅由字符 ‘0’ 和 ‘1’ 组成的字符串 s 。一步操作中&#xff0c;你可以将任一 ‘0’ 变成 ‘1’ &#xff0c;或者将 ‘1’ 变成 ‘0’ 。 交替字符串 定义为&#xff1a;如果字符串中不存在相邻两个字符相等的情况&#xff0c;那么该字符串就是交替字符…