一个完整的Flutter聊天UI套件
此Flutter包为您提供了一个基础结构以及一套工具,可让您快速构建现代化的聊天UI。与其尝试提供满足所有人期望的“一体化”小部件,不如为您提供一些可作为示例并可随意自定义的助手。
特点
- 支持群聊
- 对话列表(聊天)
- 群组头像
- 未读消息徽章
- 消息标题(用户)
- 消息头像
- 根据相对位置自适应的消息容器
- 具有数据管理API(添加,删除,更新)的控制器
- 自动选择管理
- 带有输入事件的消息输入
- 文本、图片、音频和视频消息示例
入门
首先,将以下行添加到您的pubspec.yaml依赖项中
chat_ui_kit: ^[latest_version]
接下来,设置您的模型以继承基本模型
class ChatMessage extends MessageBase {
//...
ChatUser author;
String text;
@override
DateTime get createdAt =>
DateTime.fromMillisecondsSinceEpoch(creationTimestamp);
@override
String get id => messageId;
@override
String get url => attachment;
@override
MessageBaseType get messageType {
//...
}
}
class ChatUser extends UserBase {
//...
@override
String get name => username;
@override
String get id => userid;
@override
String get avatar => avatarURL;
}
class Chat extends ChatBase {
//...
List<ChatUser> members;
ChatMessage lastMessage;
@override
int get unreadCount => chat.unreadCount;
@override
String get name {
if ((chat?.name ?? null).isNotNullOrEmpty()) return chat.name;
return membersWithoutSelf.map((e) => e.username).toList().join(", ");
}
@override
String get id => chat?.id;
@override
List<ChatUser> get membersWithoutSelf {
List<ChatUser> membersWithoutSelf = [];
final localUserId = chat?.localUserId ??
FirebaseAuth.instance.currentUser?.uid;
for (ChatUser chatUser in members) {
if (localUserId != chatUser.userid) membersWithoutSelf.add(chatUser);
}
return membersWithoutSelf;
}
}
ChatsListScreen
ChatsListController controller = ChatsListController();
ChatsList(
controller: _controller,
appUserId: _currentUser.id,
scrollHandler: _handleScrollEvent,
groupAvatarStyle: GroupAvatarStyle(withSeparator: true),
builders: ChatsListTileBuilders(
groupAvatarBuilder:
(context, imageIndex, itemIndex, size, item) {
final chat = item as Chat;
return CachedNetworkImage(
cacheManager: CustomCacheManager(),
imageUrl: chat.membersWithoutSelf[imageIndex].avatar,
width: size.width,
height: size.height,
fit: BoxFit.cover,
errorWidget: (ctx, url, val) =>
AppErrorWidget(true, size: size));
},
lastMessageBuilder: _buildLastMessage,
wrapper: _buildTileWrapper,
dateBuilder: (context, date) => Padding(
padding: EdgeInsets.only(left: 16),
child: Text(DateFormatter.getVerboseDateTimeRepresentation(
context, date)))))
@override
void dispose() {
_controller.dispose();
super.dispose();
}
ChatScreen
final MessagesListController _controller = MessagesListController();
@override
void initState() {
_controller.selectionEventStream.listen((event) {
setState(() {
_selectedItemsCount = event.currentSelectionCount;
});
});
super.initState();
}
Widget _buildMessagesList() {
IncomingMessageTileBuilders incomingBuilders = _isGroupChat
? IncomingMessageTileBuilders(
bodyBuilder: (context, index, item, messagePosition) =>
_buildMessageBody(context, index, item, messagePosition,
MessageFlow.incoming),
avatarBuilder: (context, index, item, messagePosition) {
final _chatMessage = item as ChatMessage;
return Padding(
padding:
EdgeInsets.only(right: 16),
child: _buildAvatarWithScore(_chatMessage.author));
})
: IncomingMessageTileBuilders(
bodyBuilder: (context, index, item, messagePosition) =>
_buildMessageBody(context, index, item, messagePosition,
MessageFlow.incoming),
titleBuilder: null);
return Expanded(
child: MessagesList(
controller: _controller,
appUserId: _currentUser.id,
useCustomTile: (i, item, pos) {
final msg = item as ChatMessage;
return msg.isTypeEvent;
},
messagePosition: _messagePosition,
builders: MessageTileBuilders(
customTileBuilder: _buildEventMessage,
customDateBuilder: _buildDate,
incomingMessageBuilders: incomingBuilders,
outgoingMessageBuilders: OutgoingMessageTileBuilders(
bodyBuilder: (context, index, item, messagePosition) =>
_buildMessageBody(context, index, item,
messagePosition, MessageFlow.outgoing)))));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}