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

2025-06-02 21:42:38
116次阅读
0个评论

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

效果演示

img_c9e7bd3f.png

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. 聊天组件的封装与复用

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

收藏00

登录 后评论。没有帐号? 注册 一个。