37.[HarmonyOS NEXT Row案例五] 构建智能聊天气泡:Row组件的reverse属性妙用

简介: 在即时通讯应用中,聊天气泡是一个核心UI元素,它需要能够区分发送方和接收方的消息,并以不同的样式和位置显示。本教程将详细讲解如何使用HarmonyOS NEXT的Row组件创建反向排列的消息气泡,重点介绍reverse属性的巧妙应用,帮助开发者构建出专业、美观的聊天界面。


项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示


1. 概述

在即时通讯应用中,聊天气泡是一个核心UI元素,它需要能够区分发送方和接收方的消息,并以不同的样式和位置显示。本教程将详细讲解如何使用HarmonyOS NEXT的Row组件创建反向排列的消息气泡,重点介绍reverse属性的巧妙应用,帮助开发者构建出专业、美观的聊天界面。

2. 聊天气泡的设计原则

在设计聊天气泡时,需要考虑以下几个关键原则:

  1. 区分发送方和接收方:通常通过气泡的位置(左侧或右侧)和颜色来区分。
  2. 视觉一致性:气泡的形状、大小和样式应保持一致,只是位置和颜色有所不同。
  3. 适应内容长度:气泡应能够根据文本内容的长度自动调整大小。
  4. 清晰的视觉层次:消息之间应有足够的间距,形成清晰的视觉层次。

3. 案例分析:反向排列的消息气泡

本案例展示了如何创建一个简单的聊天界面,通过Row组件的reverse属性实现消息气泡的左右排列,并通过不同的背景色区分发送方和接收方。

3.1 完整代码

@Component
export struct ChatBubbleExample {
    private messages: string[] = ['你好!', '今天天气不错', 'HarmonyOS开发很高效']
    build() {
        Column()
           {
            ForEach(this.messages, (msg:string, index) => {
                Row() {
                    Text(msg)
                        .padding({ left: 20,right:20, top: 12, bottom: 12  })
                        .backgroundColor(index % 2 === 0 ? 0x007DFF : 0xFFFFFF)
                        .fontColor(index % 2 === 0 ? 0xFFFFFF : 0x000000)
                        .borderRadius(24)
                }
                 .margin({bottom: 12})
                .reverse(index % 2 === 1)
                .justifyContent(index % 2 === 0 ? FlexAlign.End : FlexAlign.Start)
            }, (msg:string) => msg)
        } .width('100%')
        .padding(24)
    }
}

3.2 代码详解

3.2.1 组件声明与数据定义

@Component
export struct ChatBubbleExample {
    private messages: string[] = ['你好!', '今天天气不错', 'HarmonyOS开发很高效']

这部分代码声明了一个名为ChatBubbleExample的自定义组件,并定义了一个私有数组messages,包含三条示例消息。在实际应用中,这些消息通常来自数据库或网络请求。

3.2.2 外层容器设置

Column()
   {
    // 子组件
} .width('100%')
.padding(24)

这部分代码创建了一个Column容器,用于垂直排列消息气泡。Column容器的属性设置如下:

属性

说明

width

'100%'

容器宽度为父容器的100%

padding

24

容器四周内边距为24vp

这些设置确保了聊天界面有足够的空间显示消息,并且与屏幕边缘保持适当的距离。

3.2.3 消息循环渲染

ForEach(this.messages, (msg:string, index) => {
    // 单条消息的渲染逻辑
}, (msg:string) => msg)

这部分代码使用ForEach组件循环渲染消息数组中的每一条消息。ForEach接收三个参数:

  1. 要循环的数组:this.messages
  2. 渲染函数:(msg:string, index) => { ... },接收当前项和索引作为参数
  3. 唯一键函数:(msg:string) => msg,用于标识每一项,优化重渲染性能

在渲染函数中,我们为每条消息创建一个Row容器和一个Text组件。

3.2.4 单条消息的Row容器

Row() {
    Text(msg)
        .padding({ left: 20,right:20, top: 12, bottom: 12  })
        .backgroundColor(index % 2 === 0 ? 0x007DFF : 0xFFFFFF)
        .fontColor(index % 2 === 0 ? 0xFFFFFF : 0x000000)
        .borderRadius(24)
}
.margin({bottom: 12})
.reverse(index % 2 === 1)
.justifyContent(index % 2 === 0 ? FlexAlign.End : FlexAlign.Start)

这部分代码为每条消息创建一个Row容器,并在其中放置一个Text组件显示消息内容。Row容器的属性设置如下:

属性

说明

margin

{bottom: 12}

底部外边距为12vp,使消息之间有足够的间距

reverse

index % 2 === 1

根据索引奇偶性决定是否反转子组件排列顺序

justifyContent

index % 2 === 0 ? FlexAlign.End : FlexAlign.Start

根据索引奇偶性决定子组件在主轴上的对齐方式

这些设置实现了消息气泡的左右排列:偶数索引的消息(发送方)靠右对齐,奇数索引的消息(接收方)靠左对齐。

3.2.5 消息文本组件

Text(msg)
    .padding({ left: 20,right:20, top: 12, bottom: 12  })
    .backgroundColor(index % 2 === 0 ? 0x007DFF : 0xFFFFFF)
    .fontColor(index % 2 === 0 ? 0xFFFFFF : 0x000000)
    .borderRadius(24)

这部分代码创建了一个Text组件,显示消息内容。Text组件的属性设置如下:

属性

说明

padding

{ left: 20, right: 20, top: 12, bottom: 12 }

设置内边距,使文本不会贴近气泡边缘

backgroundColor

index % 2 === 0 ? 0x007DFF : 0xFFFFFF

根据索引奇偶性设置背景色:偶数为蓝色,奇数为白色

fontColor

index % 2 === 0 ? 0xFFFFFF : 0x000000

根据索引奇偶性设置文字颜色:偶数为白色,奇数为黑色

borderRadius

24

设置边框圆角为24vp,使文本呈现为气泡形状

这些设置实现了不同样式的消息气泡:发送方的消息是蓝色背景、白色文字,接收方的消息是白色背景、黑色文字。

4. reverse属性的深入解析

reverse属性是Row组件的一个重要特性,它可以反转子组件的排列顺序,在聊天气泡这种需要左右排列的场景中非常有用。

4.1 reverse属性的工作原理

reverse属性设置为true时,Row组件会将子组件按照从右到左的顺序排列,而不是默认的从左到右。这相当于将整个Row容器水平翻转。

.reverse(index % 2 === 1) // 奇数索引的消息反转排列

在本案例中,我们根据消息的索引奇偶性来决定是否反转排列:

  • 偶数索引(index % 2 === 0):不反转,从左到右排列
  • 奇数索引(index % 2 === 1):反转,从右到左排列

4.2 reverse与justifyContent的配合使用

在聊天气泡场景中,reverse属性通常与justifyContent属性配合使用,以实现消息的左右对齐。

.reverse(index % 2 === 1)
.justifyContent(index % 2 === 0 ? FlexAlign.End : FlexAlign.Start)

这种配合使用的逻辑如下:

消息类型

索引

reverse

justifyContent

效果

发送方

偶数

false

FlexAlign.End

消息靠右对齐

接收方

奇数

true

FlexAlign.Start

消息靠左对齐

通过这种配合,我们可以实现发送方消息靠右、接收方消息靠左的效果,同时保持气泡的形状和样式一致。

5. 聊天气泡的样式优化

为了提升聊天气泡的视觉效果,我们可以进行以下优化:

5.1 气泡形状优化

通过调整borderRadius属性,可以创建更符合直觉的气泡形状:

// 发送方气泡(右侧)
.borderRadius({
    topLeft: 24,
    topRight: 24,
    bottomLeft: 24,
    bottomRight: 4 // 右下角圆角较小,形成尖角效果
})
// 接收方气泡(左侧)
.borderRadius({
    topLeft: 24,
    topRight: 24,
    bottomLeft: 4, // 左下角圆角较小,形成尖角效果
    bottomRight: 24
})

5.2 气泡阴影效果

添加阴影可以增强气泡的立体感:

.shadow({
    radius: 4,
    color: 0x33000000,
    offsetX: 2,
    offsetY: 2
})

5.3 文本内容优化

对于长文本,可以设置最大宽度和自动换行:

Text(msg)
    .maxLines(0) // 不限制行数,自动换行
    .maxWidth('70%') // 最大宽度为容器的70%

6. 聊天界面的扩展功能

基于本案例的基本结构,我们可以扩展更多功能:

6.1 消息时间戳

在每条消息下方添加时间戳:

Row() {
    Column() {
        Text(msg)
            // 气泡样式
        
        Text('10:30') // 时间戳
            .fontSize(12)
            .fontColor(0x999999)
            .margin({ top: 4 })
            .alignSelf(index % 2 === 0 ? ItemAlign.End : ItemAlign.Start)
    }
}

6.2 消息状态指示

为发送方消息添加状态指示(已发送、已读等):

Row() {
    Column() {
        Text(msg)
            // 气泡样式
        
        if (index % 2 === 0) { // 只为发送方消息添加状态
            Row() {
                Text('已读')
                    .fontSize(12)
                    .fontColor(0x999999)
                
                Image($r('app.media.read')) // 已读图标
                    .width(12)
                    .height(12)
            }
            .margin({ top: 4 })
            .alignSelf(ItemAlign.End)
        }
    }
}

6.3 头像显示

在消息旁边添加用户头像:

Row() {
    if (index % 2 === 1) { // 接收方消息,左侧显示头像
        Image($r('app.media.avatar'))
            .width(36)
            .height(36)
            .borderRadius(18)
            .margin({ right: 8 })
    }
    
    Text(msg)
        // 气泡样式
    
    if (index % 2 === 0) { // 发送方消息,右侧显示头像
        Image($r('app.media.my_avatar'))
            .width(36)
            .height(36)
            .borderRadius(18)
            .margin({ left: 8 })
    }
}

7. 聊天组件的封装与复用

为了提高代码复用性,可以将聊天气泡封装为独立组件:

@Component
export struct ChatBubble {
    message: string
    isSender: boolean
    timestamp?: string
    status?: string
    avatar?: Resource
    
    build() {
        Row() {
            if (!this.isSender && this.avatar) {
                Image(this.avatar)
                    .width(36)
                    .height(36)
                    .borderRadius(18)
                    .margin({ right: 8 })
            }
            
            Column() {
                Text(this.message)
                    .padding({ left: 20, right: 20, top: 12, bottom: 12 })
                    .backgroundColor(this.isSender ? 0x007DFF : 0xFFFFFF)
                    .fontColor(this.isSender ? 0xFFFFFF : 0x000000)
                    .borderRadius({
                        topLeft: 24,
                        topRight: 24,
                        bottomLeft: this.isSender ? 24 : 4,
                        bottomRight: this.isSender ? 4 : 24
                    })
                    .maxWidth('70%')
                
                if (this.timestamp) {
                    Text(this.timestamp)
                        .fontSize(12)
                        .fontColor(0x999999)
                        .margin({ top: 4 })
                        .alignSelf(this.isSender ? ItemAlign.End : ItemAlign.Start)
                }
                
                if (this.isSender && this.status) {
                    Text(this.status)
                        .fontSize(12)
                        .fontColor(0x999999)
                        .margin({ top: 4 })
                        .alignSelf(ItemAlign.End)
                }
            }
            
            if (this.isSender && this.avatar) {
                Image(this.avatar)
                    .width(36)
                    .height(36)
                    .borderRadius(18)
                    .margin({ left: 8 })
            }
        }
        .width('100%')
        .margin({ bottom: 16 })
        .justifyContent(this.isSender ? FlexAlign.End : FlexAlign.Start)
    }
}

然后在聊天界面中使用这个组件:

@Entry
@Component
struct ChatPage {
    private messages: Array<{
        content: string,
        isSender: boolean,
        timestamp: string,
        status?: string,
        avatar?: Resource
    }> = [
        {
            content: '你好!',
            isSender: true,
            timestamp: '10:30',
            status: '已读',
            avatar: $r('app.media.my_avatar')
        },
        {
            content: '你好,有什么可以帮到你?',
            isSender: false,
            timestamp: '10:31',
            avatar: $r('app.media.avatar')
        }
    ]
    
    build() {
        Column() {
            ForEach(this.messages, (item, index) => {
                ChatBubble({
                    message: item.content,
                    isSender: item.isSender,
                    timestamp: item.timestamp,
                    status: item.status,
                    avatar: item.avatar
                })
            }, (item, index) => index.toString())
        }
        .width('100%')
        .padding(16)
    }
}

8. 总结

本教程详细讲解了如何使用HarmonyOS NEXT的Row组件创建反向排列的消息气泡,重点介绍了reverse属性的巧妙应用。通过本案例,我们学习了:

  1. 聊天气泡的设计原则
  2. Row组件的基本用法和参数设置
  3. reverse属性的工作原理及其与justifyContent的配合使用
  4. 聊天气泡的样式优化技巧
  5. 聊天界面的扩展功能
  6. 聊天组件的封装与复用

掌握这些知识点后,你可以设计出美观、易用、专业的聊天界面,提升应用的用户体验。在实际开发中,可以根据具体需求调整气泡样式、布局和功能,创建符合应用设计风格的聊天界面。

目录
打赏
0
3
3
0
46
分享
相关文章
鸿蒙NEXT时代你所不知道的全平台跨端框架:CMP、Kuikly、Lynx、uni-app x等
本篇基于当前各大活跃的跨端框架的现状,对比当前它们的情况和未来的可能,帮助你在选择框架时更好理解它们的特点和差异。
74 0
纯血鸿蒙NEXT即时通讯/IM系统:RinbowTalk正式发布,全源码、纯ArkTS编写
RainbowTalk是一套基于MobileIMSDK的产品级鸿蒙NEXT端IM系统,目前已正式发布。纯ArkTS、从零编写,无套壳、没走捷径,每一行代码都够“纯”(详见:《RainbowTalk详细介绍》)。 MobileIMSDK是一整套开源IM即时通讯框架,历经10年,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp、鸿蒙NEXT,服务端基于Netty编写。
82 1
鸿蒙NEXT-鸿蒙三层架构搭建,嵌入HMRouter,实现便捷跳转,新手攻略。(2/3)
本文介绍在三层架构中实现模块依赖的步骤。首先在产品定制层(features)的oh-package.json5文件中导入共享包依赖,如"basic":"file:../../commons/basic"。然后在产品层(products)的配置文件中同时导入公共能力层和产品定制层的依赖,示例展示了如何添加"basic"和"my"两个依赖项。通过这些配置,三层架构的各模块之间建立了完整的依赖关系。
103 0
鸿蒙NEXT-鸿蒙三层架构搭建,嵌入HMRouter,实现便捷跳转,新手攻略。(2/3)
【HarmonyOS 5】鸿蒙组件&模板服务详解 - 助力高效开发的利器
在移动应用开发领域,效率与质量始终是开发者追求的核心目标。鸿蒙系统作为新兴的操作系统,为开发者提供了丰富且强大的开发资源,其中鸿蒙组件&模板服务更是成为开发者快速构建高质量应用的得力助手。
93 0
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
HarmonyOS NEXT仓颉开发语言实战案例:健身App
本期分享一个健身App首页的布局实现,顶部采用Stack容器实现重叠背景与偏移效果,列表部分使用List结合Scroll实现可滚动内容。代码结构清晰,适合学习HarmonyOS布局技巧。
HarmonyOS NEXT仓颉开发语言实战案例:银行App
仓颉语言银行App项目分享,页面布局采用List容器,实现沉浸式体验与模块化设计。顶部资产模块结合Stack与Row布局,背景图与内容分离,代码清晰易懂;功能按钮部分通过负边距实现上移效果,圆角仅保留顶部;热门推荐使用header组件,结构更规范。整体代码风格与ArkTS相似,但细节更灵活,适合金融类应用开发。
鸿蒙开发:基于最新API,如何实现组件化运行
手动只是让大家了解切换的原理,在实际开发中,可不推荐手动,下篇文章,我们将通过脚本或者插件,快速实现组件化模块之间的切换,实现独立运行,敬请期待!
101 0
鸿蒙开发:基于最新API,如何实现组件化运行
鸿蒙开发:资讯项目实战之项目初始化搭建
目前来说,我们的资讯项目只是往前迈了很小的一步,仅仅实现了项目创建,步虽小,但概念性的知识很多,这也是这个项目的初衷,让大家不仅仅可以掌握日常的技术开发,也能让大家理解实际的项目开发知识。
鸿蒙开发:资讯项目实战之项目初始化搭建
鸿蒙5开发宝藏案例分享---优化应用时延问题
鸿蒙性能优化指南来了!从UI渲染到数据库操作,6大实战案例助你提升应用流畅度。布局层级优化、数据加载并发、数据库查询提速、相机资源延迟释放、手势识别灵敏调整及转场动画精调,全面覆盖性能痛点。附赠性能自检清单,帮助开发者高效定位问题,让应用运行如飞!来自华为官方文档的精华内容,建议收藏并反复研读,共同探讨更多优化技巧。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问