Skip to content

自定义消息页面(MessagesView)

杜洁鹏 edited this page Jun 7, 2024 · 2 revisions

自定义消息页面

消息页面提供了两种方式构造,两种方式都提供了对消息页面的自定义参数。

MessagesView()

const MessagesView({
    required this.profile,
    this.appBar,
    this.enableAppBar = true,
    this.title,
    this.inputBar,
    this.controller,
    this.showMessageItemAvatar,
    this.showMessageItemNickname,
    this.onItemTap,
    this.onItemLongPress,
    this.longPressActions,
    this.onItemLongPressHandler,
    this.onDoubleTap,
    this.onAvatarTap,
    this.onAvatarLongPress,
    this.onNicknameTap,
    this.emojiWidget,
    this.itemBuilder,
    this.alertItemBuilder,
    this.bubbleStyle = ChatUIKitMessageListViewBubbleStyle.arrow,
    this.morePressActions,
    this.onMoreActionsItemsHandler,
    this.replyBarBuilder,
    this.quoteBuilder,
    this.onErrorBtnTapHandler,
    this.bubbleBuilder,
    this.bubbleContentBuilder,
    this.forceLeft,
    this.inputBarTextEditingController,
    this.multiSelectBottomBar,
    this.viewObserver,
    this.attributes,
    this.onReactionItemTap,
    this.onReactionInfoTap,
    this.reactionItemsBuilder,
    this.onThreadItemTap,
    this.threadItemBuilder,
    this.appBarTrailingActionsBuilder,
    super.key,
  });

设置消息接收方信息

  @override
  // profile: 消息接收方的信息, 可以是 `ChatUIKitProfile.contact` 或者 `ChatUIKitProfile.group`
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.gr(id: chatter),
    );
  }

设置 AppBar

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      appBar: AppBar(title: const Text('test')),
    );
  }

设置 是否开启 AppBar

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      enableAppBar: false,
    );
  }

设置 默认 AppBar 标题

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      title: 'Chat',
    );
  }

默认 AppBar 右侧按钮自定义

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.group(id: groupId),
      // defaultList: 默认的菜单项。
      appBarTrailingActionsBuilder: (context, defaultList) {
        return defaultList;
      },
    );
  }

设置控制器

MessageListViewController 是 uikit 内部用来获取和操作数据用的控制器。

  @override
  Widget build(BuildContext context) {
    final profile = ChatUIKitProfile.contact(id: chatter);
    // 需要注意,构造 `MessageListViewController` 的 `profile` 要与构造 `MessagesView` 的一致。
    final MessageListViewController controller = MessageListViewController(profile: profile);
    return MessagesView(
      profile: profile,
      controller: controller,
    );
  }
}

设置输入框

如果自定义输入框,需要将输入框内的文字通过 MessageListViewController 发送。

  final TextEditingController textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final profile = ChatUIKitProfile.contact(id: chatter);
    // 需要注意,构造 `MessageListViewController` 的 `profile` 要与构造 `MessagesView` 的一致。
    final MessageListViewController controller = MessageListViewController(profile: profile);
    return MessagesView(
      profile: profile,
      controller: controller,
      inputBar: Row(
        children: [
          Expanded(
            child: TextField(
              controller: textController,
            ),
          ),
          InkWell(
            onTap: () {
              controller.sendTextMessage(textController.text);
              textController.clear();
            },
            child: const SizedBox(
              width: 40,
              child: Text('Send'),
            ),
          )
        ],
      ),
    );
  }

设置是否显示头像

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      showMessageItemAvatar: (model) {
        return false;
      },
    );
  }

设置是否显示昵称

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      showMessageItemNickname: (model) {
        return false;
      },
    );
  }

设置消息点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      onItemTap: (context, model) {
        return false;
      },
    );
  }

设置长按消息事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // 长按弹出菜单,返回 [] 则不弹出菜单
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息。
      // defaultActions 默认的菜单项,包括了复制,删除等操作
      onItemLongPressHandler: (context, model, defaultActions) {
        return defaultActions;
      },
    );
  }

设置消息双击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      onDoubleTap: (context, model) {
        return false;
      },
    );
  }

设置头像点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      onAvatarTap: (context, model) {
        return false;
      },
    );
  }

设置昵称点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      onNicknameTap: (context, model) {
        return false;
      },
    );
  }

设置表情弹出菜单

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      emojiWidget: Container(
        height: 200,
        color: Colors.red,
      ),
    );
  }

设置消息显示样式

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      itemBuilder: (context, model) {
        return ListTile(
          title: Text(model.message.textContent),
        );
      },
    );
  }

设置提示消息样式

提示消息主要是指 撤回消息,或者是加群之类的消息。

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      alertItemBuilder: (context, model) {
        return const Text('XXX撤回了一条消息');
      },
    );
  }

设置消息气泡样式

UIKit 提供了两种气泡样式,默认是 ChatUIKitMessageListViewBubbleStyle.arrow

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      bubbleStyle: ChatUIKitMessageListViewBubbleStyle.noArrow,
    );
  }

设置输入框上“更多”按钮点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      morePressActions: [
        ChatUIKitBottomSheetItem.normal(label: 'take photo'),
      ],
    );
  }

设置输入框上“更多”按钮弹出菜单

也可以对 “更多” 按钮就行动态配置,当菜单弹出前才进行构建。

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // defaultActions 默认要弹出的菜单,可以返回自己定义的菜单
      onMoreActionsItemsHandler: (context, defaultActions) {
        return defaultActions;
      },
    );
  }
}

设置消息引用消息的展示样式

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      quoteBuilder: (context, model) {
        return const Text('model.message');
      },
    );
  }

自定义消息气泡样式

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // child: 消息内容 widget
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      bubbleBuilder: (context, child, model) {
        return Container(
          color: Colors.red,
          padding: const EdgeInsets.all(8),
          child: child,
        );
      },
    );
  }

自定义消息气泡中内容

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
      bubbleContentBuilder: (context, model) {
        return const Text('自定义内容');
      },
    );
  }

是否强制消息都在左侧

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      forceLeft: true,
    );
  }

多选时 bottom widget

  @override
  Widget build(BuildContext context) {
    // 多选后需要通过 `MessageListViewController` 得到选择的信息,所以需要构建一个 `MessageListViewController` 对象。
    // 构建 `MessageListViewController` 时需要确保和构建 `MessagesView` 使用是使用的是一个 `profile` 。
    final profile = ChatUIKitProfile.contact(id: chatter);
    final MessageListViewController controller = MessageListViewController(profile: profile);

    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      controller: controller,
      multiSelectBottomBar: Row(
        children: [
          Expanded(
            child: TextButton.icon(
              onPressed: () {
                if (controller.selectedMessages.isNotEmpty) {
                  // 跳转到 转发选择联系人页面
                  ChatUIKitRoute.pushOrPushNamed(
                    context,
                    ChatUIKitRouteNames.forwardMessageSelectView,
                    ForwardMessageSelectViewArguments(
                      messages: controller.selectedMessages,
                      isMulti: true,
                    ),
                  ).then((value) {
                    if (value == true) {
                      // 返回后需要关闭多选状态
                      controller.disableMultiSelectMode();
                    }
                  });
                }
              },
              icon: const Icon(Icons.forward_10),
              label: const Text('转发'),
            ),
          )
        ],
      ),
    );
  }

reaction 详情按钮点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      // 只有群组支持 reaction
      profile: ChatUIKitProfile.group(id: groupId),
      // 点击后,默认弹出当前消息所有 `reaction` 的操作人员,返回 `true` 为需要拦截,返回 `false` 则表示不拦截,使用默认实现。
      onReactionInfoTap: (context, model) {
        return true;
      },
    );
  }

## MessagesView.arguments()

通过arguments的构造主要用于路由跳转时,当uikit内部进行页面跳转时,可以通过 RouteSettings 得到 arguments,你可以对它进行赋值和定义,之后将它重新放到 RouteSettings 中并返回。 这样在跳转到的新页面就会按照你设置的 arguments 就行创建。 当然,也允许直接使用 arguments 进行页面构造,下面将介绍如何直接使用 arguments 进行构造和自定义。

 MessagesViewArguments({
    required this.profile,
    this.controller,
    this.appBar,
    this.title,
    this.inputBar,
    this.showMessageItemAvatar,
    this.showMessageItemNickname,
    this.onItemTap,
    this.onDoubleTap,
    this.onAvatarTap,
    this.onAvatarLongPress,
    this.onNicknameTap,
    this.emojiWidget,
    this.itemBuilder,
    this.alertItemBuilder,
    this.morePressActions,
    this.bubbleStyle = ChatUIKitMessageListViewBubbleStyle.arrow,
    this.replyBarBuilder,
    this.quoteBuilder,
    this.onErrorBtnTapHandler,
    this.bubbleBuilder,
    this.enableAppBar = true,
    this.bubbleContentBuilder,
    this.onMoreActionsItemsHandler,
    this.onItemLongPressHandler,
    this.inputBarTextEditingController,
    this.forceLeft,
    this.multiSelectBottomBar,
    this.viewObserver,
    this.attributes,
    this.onReactionItemTap,
    this.onReactionInfoTap,
    this.reactionItemsBuilder,
    this.onThreadItemTap,
    this.threadItemBuilder,
    this.appBarTrailingActionsBuilder,
  });

设置消息接收方信息

  @override
  // profile: 消息接收方的信息, 可以是 `ChatUIKitProfile.contact` 或者 `ChatUIKitProfile.group`
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
      ),
    );
  }

设置 AppBar

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        appBar: AppBar(title: const Text('test')),
      ),
    );
  }

设置 是否开启 AppBar

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        enableAppBar: false,
      ),
    );
  }

设置 默认 AppBar 标题

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        title: 'Chat',
      ),
    );
  }

默认 AppBar 右侧按钮自定义

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // defaultList: 默认的菜单项。
        appBarTrailingActionsBuilder: (context, defaultList) {
          return defaultList;
        },
      ),
    );
  }

设置控制器

MessageListViewController 是 uikit 内部用来获取和操作数据用的控制器。

  @override
  Widget build(BuildContext context) {
    final profile = ChatUIKitProfile.contact(id: chatter);
    // 需要注意,构造 `MessageListViewController` 的 `profile` 要与构造 `MessagesView` 的一致。
    final MessageListViewController controller = MessageListViewController(profile: profile);
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        controller: controller,
      ),
    );
  }

设置输入框

如果自定义输入框,需要将输入框内的文字通过 MessageListViewController 发送。

  final TextEditingController textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final profile = ChatUIKitProfile.contact(id: chatter);
    // 需要注意,构造 `MessageListViewController` 的 `profile` 要与构造 `MessagesView` 的一致。
    final MessageListViewController controller = MessageListViewController(profile: profile);
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: profile,
        controller: controller,
        inputBar: Row(
          children: [
            Expanded(
              child: TextField(
                controller: textController,
              ),
            ),
            InkWell(
              onTap: () {
                controller.sendTextMessage(textController.text);
                textController.clear();
              },
              child: const SizedBox(
                width: 40,
                child: Text('Send'),
              ),
            )
          ],
        ),
      ),
    );
  }

设置是否显示头像

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        showMessageItemAvatar: (model) {
          return false;
        },
      ),
    );
  }

设置是否显示昵称

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        showMessageItemNickname: (model) {
          return false;
        },
      ),
    );
  }

设置消息点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        onItemTap: (context, model) {
          return false;
        },
      ),
    );
  }

设置长按消息事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // 长按弹出菜单,返回 [] 则不弹出菜单
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息。
        // defaultActions 默认的菜单项,包括了复制,删除等操作
        onItemLongPressHandler: (context, model, defaultActions) {
          return defaultActions;
        },
      ),
    );
  }

设置消息双击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        onDoubleTap: (context, model) {
          return false;
        },
      ),
    );
  }

设置头像点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        onAvatarTap: (context, model) {
          return false;
        },
      ),
    );
  }

设置昵称点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // 如果你需要拦截点击事件返回 `true`, 如果你不处理,返回 `false`
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        onNicknameTap: (context, model) {
          return false;
        },
      ),
    );
  }

设置表情弹出菜单

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        emojiWidget: Container(
          height: 200,
          color: Colors.red,
        ),
      ),
    );
  }

设置消息显示样式

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        itemBuilder: (context, model) {
          return ListTile(
            title: Text(model.message.textContent),
          );
        },
      ),
    );
  }

设置提示消息样式

提示消息主要是指 撤回消息,或者是加群之类的消息。

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        alertItemBuilder: (context, model) {
          return const Text('XXX撤回了一条消息');
        },
      ),
    );
  }

设置消息气泡样式

UIKit 提供了两种气泡样式,默认是 ChatUIKitMessageListViewBubbleStyle.arrow

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        bubbleStyle: ChatUIKitMessageListViewBubbleStyle.noArrow,
      ),
    );
  }

设置输入框上“更多”按钮点击事件

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        morePressActions: [
          ChatUIKitBottomSheetItem.normal(label: 'take photo'),
        ],
      ),
    );
  }

设置输入框上“更多”按钮弹出菜单

也可以对 “更多” 按钮就行动态配置,当菜单弹出前才进行构建。

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // defaultActions 默认要弹出的菜单,可以返回自己定义的菜单
        onMoreActionsItemsHandler: (context, defaultActions) {
          return defaultActions;
        },
      ),
    );
  }

设置消息引用消息的展示样式

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        quoteBuilder: (context, model) {
          return const Text('model.message');
        },
      ),
    );
  }

自定义消息气泡样式

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // child: 消息内容 widget
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        bubbleBuilder: (context, child, model) {
          return Container(
            color: Colors.red,
            padding: const EdgeInsets.all(8),
            child: child,
          );
        },
      ),
    );
  }

自定义消息气泡中内容

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        // model 头像对应的消息数据,包括了消息的内容和消息的发送,接收方等信息
        bubbleContentBuilder: (context, model) {
          return const Text('自定义内容');
        },
      ),
    );
  }

是否强制消息都在左侧

  @override
  Widget build(BuildContext context) {
    return MessagesView(
      profile: ChatUIKitProfile.contact(id: chatter),
      forceLeft: true,
    );
  }

多选时 bottom widget

  @override
  Widget build(BuildContext context) {
    return MessagesView.arguments(
      MessagesViewArguments(
        profile: ChatUIKitProfile.contact(id: chatter),
        controller: controller,
        multiSelectBottomBar: Row(
          children: [
            Expanded(
              child: TextButton.icon(
                onPressed: () {
                  if (controller.selectedMessages.isNotEmpty) {
                    // 跳转到 转发选择联系人页面
                    ChatUIKitRoute.pushOrPushNamed(
                      context,
                      ChatUIKitRouteNames.forwardMessageSelectView,
                      ForwardMessageSelectViewArguments(
                        messages: controller.selectedMessages,
                        isMulti: true,
                      ),
                    ).then((value) {
                      if (value == true) {
                        // 返回后需要关闭多选状态
                        controller.disableMultiSelectMode();
                      }
                    });
                  }
                },
                icon: const Icon(Icons.forward_10),
                label: const Text('转发'),
              ),
            )
          ],
        ),
      ),
    );
  }
Clone this wiki locally