聊天页面

大约 4 分钟

聊天页面

用户可以在聊天页面中进行单聊、群聊或聊天室聊天。该页面分为消息列表和消息输入区域。

创建聊天界面

em_chat_uikit 提供了 ChatMessagesView,添加到 build 中并传入相应的参数即可用。

参数类型是否必需描述
conversationEMConversationChatMessagesView 对应的会话对象。
inputBarTextEditingController输入框中的 TextField 对应的 Controller。
backgroundChatMessagesView 的背景图。
inputBar输入框组件。 如不设置,默认使用 ChatInputBar
onTap消息气泡点击事件。
onBubbleLongPress消息气泡长按事件。
onBubbleDoubleTap消息气泡双击事件。
avatarBuilder头像 widget builder。
nicknameBuilder昵称 Widget builder。
itemBuilder消息气泡 Widget builder。
moreItems长按消息气泡后显示的操作项。如果在 onBubbleLongPress 中返回 null,将使用 moreItems。默认显示三个操作:复制、删除和消息撤回。
messageListViewController消息列表 Controller, 详见 ChatMessageListController
willSendMessage消息将要发送的事件,需要返回一个 EMMessage 对象。
onError错误回调,如权限错误等。
enableScrollBar是否启用滚动条。默认启用。
needDismissInputWidget用于取消输入 Widget 的回调。如果使用自定义输入 Widget,则在接收回调时取消输入 Widget,例如,通过调用 FocusNode.unfocus。详见 ChatInputBar
inputBarMoreActionsOnTap单击输入框旁边的 + 的回调。需要返回 ChatBottomSheetItems 列表。
class _MessagesPageState extends State<MessagesPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
        ),
      ),
    );
  }
}

自定义实现

设置主题颜色

可以通过修改主题中的属性来改变消息页面中的颜色和字体。

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      builder: (context, child) {
        // ChatUIKit 需要在你使用 `em_chat_uikit` widget 的根节点上。
        return ChatUIKit(
          // ChatUIKitTheme 主题。
          theme: ChatUIKitTheme(),
          child: child!,
        );
      },
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

参数详情如下表所示:

参数类型是否必需描述
badgeColorColor未读数角标颜色。
badgeBorderColorColor未读数 border 颜色。
badgeTextStyleTextStyle未读数角标的字体。
sendVoiceItemIconColorColor发送的语音消息 bubble 中图标的颜色。
receiveVoiceItemIconColorColor接收的语音消息 bubble 中图标的颜色。
sendBubbleColorColor发送消息的气泡颜色。
receiveBubbleColorColor收到消息的气泡颜色。
sendTextStyleTextStyle发送文字消息的字体。
receiveTextStyleTextStyle接收文字消息的字体。
conversationListItemTitleStyleTextStyle会话列表条目标题的字体。
conversationListItemSubTitleStyleTextStyle会话列表条目副标题的字体。
conversationListItemTsStyleTextStyle会话列表条目时间的字体。
messagesListItemTsStyleTextStyle消息列表条目中时间的字体。
inputWidgetSendBtnColorColor表情键盘中发送按钮的颜色。
inputWidgetSendBtnStyleTextStyle表情键盘中发送按钮的字体。

添加头像

通过设置 ChatMessagesView 中的 avatarBuilder 实现自定义头像的功能。

class _MessagesPageState extends State<MessagesPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
          avatarBuilder: (context, userId) {
            // 返回你要显示的头像 Widget。
            return Container(
              width: 30,
              height: 30,
              color: Colors.red,
            );
          },
        ),
      ),
    );
  }
}

效果如下图所示:

添加昵称

通过设置 ChatMessagesView 中的 nicknameBuilder 实现自定义昵称的功能。

class _MessagesPageState extends State<MessagesPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
          // 返回你要显示的昵称 widget。
          nicknameBuilder: (context, userId) {
            return Text(userId);
          },
        ),
      ),
    );
  }
}

效果如下图所示:

添加气泡点击事件

通过设置 ChatMessagesView 中的 onTap 实现自定义点击功能。

class _MessagesPageState extends State<MessagesPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
          // 条目点击事件。
          onTap: (context, message) {
            bubbleClicked(message);
            return true;
          },
        ),
      ),
    );
  }

  void bubbleClicked(EMMessage message) {
    SnackBar bar = const SnackBar(
      content: Text('气泡被点击'),
      duration: Duration(milliseconds: 1000),
    );
    ScaffoldMessenger.of(context).showSnackBar(bar);
  }
}

效果如下图所示:

自定义消息气泡样式

通过设置 ChatMessagesView 中的 itemBuilder 实现自定义气泡样式。

class _MessagesPageState extends State<MessagesPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
          itemBuilder: (context, model) {
            if (model.message.body.type == MessageType.TXT) {
              // 自定义消息气泡。
              return CustomTextItemWidget(
                model: model,
                onTap: (context, message) {
                  bubbleClicked(message);
                  return true;
                },
              );
            }
          },
        ),
      ),
    );
  }

  void bubbleClicked(EMMessage message) {
    SnackBar bar = const SnackBar(
      content: Text('气泡被点击'),
      duration: Duration(milliseconds: 1000),
    );
    ScaffoldMessenger.of(context).showSnackBar(bar);
  }
}


//自定义消息气泡。
class CustomTextItemWidget extends ChatMessageListItem {
  const CustomTextItemWidget({super.key, required super.model, super.onTap});

  
  Widget build(BuildContext context) {
    EMTextMessageBody body = model.message.body as EMTextMessageBody;

    Widget content = Text(
      body.content,
      style: const TextStyle(
        color: Colors.black,
        fontSize: 50,
        fontWeight: FontWeight.w400,
      ),
    );
    return getBubbleWidget(content);
  }
}

效果如下图所示:

自定义输入框样式

通过设置 ChatMessagesView 中的 inputBar 实现自定义输入框,同时用过实现 ChatMessageListController 发送信息。

class _MessagesPageState extends State<MessagesPage> {
  late ChatMessageListController _msgController;
  final TextEditingController _textController = TextEditingController();
  final FocusNode _focusNode = FocusNode();
  
  void initState() {
    super.initState();
    _msgController = ChatMessageListController(widget.conversation);
  }

  
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.conversation.id)),
      body: SafeArea(
        // UIKit 中的聊天页面。
        child: ChatMessagesView(
          conversation: widget.conversation,
          messageListViewController: _msgController,
          inputBar: customInputWidget(),
          needDismissInputWidget: () {
            _focusNode.unfocus();
          },
        ),
      ),
    );
  }

  // 自定义输入 Widget。
  Widget customInputWidget() {
    return SizedBox(
      height: 50,
      child: Row(
        children: [
          Expanded(
            child: TextField(
              focusNode: _focusNode,
              controller: _textController,
            ),
          ),
          ElevatedButton(
              onPressed: () {
                final msg = EMMessage.createTxtSendMessage(
                    targetId: widget.conversation.id,
                    content: _textController.text);
                _textController.text = '';
                _msgController.sendMessage(msg);
              },
              child: const Text('Send'))
        ],
      ),
    );
  }
}

效果如下图所示: