Flutter & OpenHarmony OA系统即时通讯聊天组件开发指南
本文介绍了使用Flutter和OpenHarmony开发即时通讯聊天组件的实现方案。Flutter端通过定义消息模型、构建消息列表和气泡组件,支持多种消息类型和状态显示;OpenHarmony端采用声明式UI开发,实现类似功能。两者都包含消息列表、输入区域、状态管理等核心功能,适用于企业OA系统的即时通讯场景。组件设计注重性能优化和跨平台兼容性,可有效提升团队协作效率。

前言
即时通讯是OA系统中促进团队协作的核心功能,它支持员工之间的实时沟通、文件共享、群组讨论等。一个优秀的聊天组件需要支持多种消息类型、消息状态管理、历史记录加载等功能。本文将详细介绍如何使用Flutter和OpenHarmony开发一个功能完善的即时通讯聊天组件,提升企业内部沟通效率。
组件功能设计
聊天组件的核心是消息列表和输入区域。消息列表需要支持文本、图片、文件、语音等多种消息类型,显示发送时间、已读状态等信息。输入区域支持文本输入、表情选择、附件上传等功能。组件还需要支持下拉加载历史消息、新消息提醒、消息搜索等功能。
Flutter端实现
定义消息类型和数据模型:
enum MessageType { text, image, file, voice, video, location }
enum MessageStatus { sending, sent, delivered, read, failed }
class ChatMessage {
final String id;
final String senderId;
final String senderName;
final String senderAvatar;
final MessageType type;
final String content;
final DateTime time;
final MessageStatus status;
final Map<String, dynamic>? extra;
ChatMessage({
required this.id,
required this.senderId,
required this.senderName,
required this.senderAvatar,
required this.type,
required this.content,
required this.time,
this.status = MessageStatus.sending,
this.extra,
});
bool get isMine => senderId == currentUserId;
}
ChatMessage模型包含消息的完整信息,extra字段存储不同类型消息的扩展数据,如图片的宽高、文件的大小等。isMine计算属性判断是否为自己发送的消息,用于决定消息的显示位置。
聊天组件的基础结构:
class ChatWidget extends StatefulWidget {
final List<ChatMessage> messages;
final Function(String) onSendText;
final Function(String) onSendImage;
const ChatWidget({
Key? key,
required this.messages,
required this.onSendText,
required this.onSendImage,
}) : super(key: key);
State<ChatWidget> createState() => _ChatWidgetState();
}
组件接收消息列表和发送回调函数,onSendText处理文本消息,onSendImage处理图片消息。这种设计使组件专注于UI展示,消息发送逻辑由父组件处理。
消息列表构建:
Widget _buildMessageList() {
return ListView.builder(
controller: _scrollController,
reverse: true,
itemCount: widget.messages.length,
itemBuilder: (context, index) {
final message = widget.messages[widget.messages.length - 1 - index];
return _buildMessageItem(message);
},
);
}
消息列表使用reverse模式,新消息显示在底部。ListView.builder实现懒加载,只渲染可见区域的消息,适合大量消息的场景。
消息气泡构建:
Widget _buildMessageItem(ChatMessage message) {
final isMine = message.isMine;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
mainAxisAlignment: isMine ? MainAxisAlignment.end : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isMine) _buildAvatar(message),
SizedBox(width: 8),
Flexible(
child: Column(
crossAxisAlignment: isMine ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
if (!isMine) Text(message.senderName, style: TextStyle(fontSize: 12, color: Colors.grey)),
_buildBubble(message),
_buildMessageStatus(message),
],
),
),
SizedBox(width: 8),
if (isMine) _buildAvatar(message),
],
),
);
}
消息项根据是否为自己发送决定布局方向,自己的消息靠右显示,他人的消息靠左显示。Flexible确保气泡不会超出屏幕宽度。
消息气泡内容:
Widget _buildBubble(ChatMessage message) {
final isMine = message.isMine;
return Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: isMine ? Colors.blue : Colors.grey.shade200,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
bottomLeft: Radius.circular(isMine ? 16 : 4),
bottomRight: Radius.circular(isMine ? 4 : 16),
),
),
child: _buildMessageContent(message),
);
}
气泡使用不同颜色区分自己和他人的消息,圆角设计使气泡有指向发送者的效果。_buildMessageContent根据消息类型渲染不同内容。
OpenHarmony鸿蒙端实现
定义消息类型和数据接口:
type MessageType = 'text' | 'image' | 'file' | 'voice' | 'video' | 'location'
type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed'
interface ChatMessage {
id: string
senderId: string
senderName: string
senderAvatar: string
type: MessageType
content: string
time: number
status: MessageStatus
extra?: Record<string, any>
}
使用联合类型定义消息类型和状态,extra使用Record类型存储扩展数据。
聊天组件的基础结构:
@Component
struct ChatWidget {
@Prop messages: ChatMessage[] = []
@State inputText: string = ''
@State showEmoji: boolean = false
private scroller: Scroller = new Scroller()
private onSendText: (text: string) => void = () => {}
private onSendImage: (path: string) => void = () => {}
}
使用@State管理输入文本和表情面板状态,Scroller用于控制消息列表滚动。
消息列表:
@Builder
MessageList() {
List({ scroller: this.scroller }) {
ForEach(this.messages, (message: ChatMessage) => {
ListItem() {
this.MessageItem(message)
}
})
}
.width('100%')
.layoutWeight(1)
.listDirection(Axis.Vertical)
}
消息列表使用List组件渲染,layoutWeight(1)使列表占据剩余空间。ForEach遍历所有消息,每条消息使用MessageItem组件展示。
消息项:
@Builder
MessageItem(message: ChatMessage) {
Row() {
if (!this.isMine(message)) {
Image(message.senderAvatar)
.width(40)
.height(40)
.borderRadius(20)
}
Column() {
if (!this.isMine(message)) {
Text(message.senderName)
.fontSize(12)
.fontColor('#999999')
}
this.MessageBubble(message)
this.MessageStatus(message)
}
.alignItems(this.isMine(message) ? HorizontalAlign.End : HorizontalAlign.Start)
.layoutWeight(1)
.margin({ left: 8, right: 8 })
if (this.isMine(message)) {
Image(message.senderAvatar)
.width(40)
.height(40)
.borderRadius(20)
}
}
.width('100%')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.justifyContent(this.isMine(message) ? FlexAlign.End : FlexAlign.Start)
}
消息项根据发送者决定布局方向,自己的消息头像在右侧,他人的消息头像在左侧。alignItems控制气泡对齐方向。
消息气泡:
@Builder
MessageBubble(message: ChatMessage) {
Column() {
if (message.type === 'text') {
Text(message.content)
.fontSize(16)
.fontColor(this.isMine(message) ? Color.White : '#333333')
} else if (message.type === 'image') {
Image(message.content)
.width(200)
.height(150)
.borderRadius(8)
.objectFit(ImageFit.Cover)
}
}
.padding(12)
.backgroundColor(this.isMine(message) ? '#1890FF' : '#F5F5F5')
.borderRadius({
topLeft: 16,
topRight: 16,
bottomLeft: this.isMine(message) ? 16 : 4,
bottomRight: this.isMine(message) ? 4 : 16
})
}
气泡根据消息类型渲染不同内容,文本消息显示文字,图片消息显示图片。borderRadius设置不对称圆角,形成指向发送者的效果。
输入区域:
@Builder
InputArea() {
Row() {
Image($r('app.media.emoji'))
.width(28)
.height(28)
.onClick(() => {
this.showEmoji = !this.showEmoji
})
TextInput({ placeholder: '输入消息', text: this.inputText })
.layoutWeight(1)
.height(40)
.margin({ left: 8, right: 8 })
.onChange((value: string) => {
this.inputText = value
})
Image($r('app.media.attachment'))
.width(28)
.height(28)
.onClick(() => this.pickImage())
Button('发送')
.type(ButtonType.Capsule)
.height(36)
.margin({ left: 8 })
.enabled(this.inputText.trim().length > 0)
.onClick(() => this.sendTextMessage())
}
.width('100%')
.padding(12)
.backgroundColor(Color.White)
}
输入区域包含表情按钮、文本输入框、附件按钮和发送按钮。发送按钮在输入内容为空时禁用,防止发送空消息。
发送消息:
private sendTextMessage() {
if (this.inputText.trim().length === 0) return
this.onSendText(this.inputText)
this.inputText = ''
setTimeout(() => {
this.scroller.scrollToIndex(this.messages.length - 1)
}, 100)
}
发送消息后清空输入框,并滚动到列表底部显示新消息。setTimeout确保消息添加到列表后再滚动。
消息状态显示:
@Builder
MessageStatus(message: ChatMessage) {
if (this.isMine(message)) {
Row() {
Text(this.formatTime(message.time))
.fontSize(10)
.fontColor('#999999')
if (message.status === 'sending') {
LoadingProgress()
.width(12)
.height(12)
.margin({ left: 4 })
} else if (message.status === 'read') {
Text('已读')
.fontSize(10)
.fontColor('#52C41A')
.margin({ left: 4 })
}
}
.margin({ top: 4 })
}
}
消息状态显示发送时间和状态标识,发送中显示加载动画,已读显示绿色"已读"文字。只有自己发送的消息显示状态信息。
总结
本文详细介绍了Flutter和OpenHarmony平台上即时通讯聊天组件的开发方法。聊天组件是OA系统中促进团队协作的核心功能,需要支持多种消息类型和状态管理。两个平台都提供了列表组件和输入组件来实现聊天界面,开发者需要注意消息的布局方向和状态显示的处理。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)