消息列表的高级设置

大约 10 分钟

消息列表的高级设置

本文详细介绍 MessageList 组件的各项高级配置功能,帮助你实现自定义的消息展示、交互监听和历史消息加载。

概述

MessageList 是聊天界面核心组件,提供如下功能:

  • 消息展示:支持文本、图片、语音、视频、文件等多种消息类型
  • 消息交互:支持点击、长按、滚动加载、附件下载等操作
  • 自定义扩展:支持自定义消息样式、交互行为和消息类型

通常,MessageList 作为 ConversationDetail 组件的一部分,与 MessageInput 配合使用。通过 ConversationDetaillist 属性可进行独立配置:

import { ConversationDetail, MessageList } from 'react-native-chat-uikit';
import type { MessageListRef } from 'react-native-chat-uikit';

function ChatScreen({ route }) {
  const { convId, convType } = route.params;
  const messageListRef = useRef<MessageListRef>(null);

  return (
    <ConversationDetail
      type="chat"
      convId={convId}
      convType={convType}
      list={{
        props: {
          // 传递给 MessageList 的属性
          onClickedItem: (id, model) => {
            console.log('点击消息:', id, model);
          },
          recvMessageAutoScroll: true,
          containerStyle: {
            backgroundColor: '#f5f5f5',
          },
        },
        // render: MessageList, // 可选:使用自定义的 MessageList 组件
        ref: messageListRef, // 获取 MessageList 的控制器
      }}
      onBack={() => navigation.goBack()}
    />
  );
}

设置容器样式

通过 containerStyle 自定义消息列表容器的样式,例如,调整背景色、内边距等:

<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      containerStyle: {
        backgroundColor: '#f9f9f9',
        paddingHorizontal: 10,
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

消息布局类型

messageLayoutType 可调整消息的排列方式,适用于客服消息、系统通知等场景。

<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      // 所有消息显示在左侧
      messageLayoutType: 'left',

      // 或所有消息显示在右侧
      // messageLayoutType: 'right',

      // 不设置则使用默认布局(发送消息在右,接收消息在左)
    },
  }}
  onBack={() => navigation.goBack()}
/>

自动滚动控制

recvMessageAutoScroll 属性控制收到新消息时是否自动滚动到底部。默认值为 false,避免打断用户浏览历史消息:

<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      recvMessageAutoScroll: true, // 收到新消息时自动滚动
    },
  }}
  onBack={() => navigation.goBack()}
/>

自定义消息条目

listItemRenderProps 是消息列表最核心的自定义属性,提供对消息渲染的细粒度控制。通过该属性,你可以完全控制消息的显示样式,包括消息气泡、内容、头像、引用消息等。

可自定义组件

listItemRenderProps 包含以下可自定义组件:

组件名称类型描述
MessageViewMessageViewRender消息视图组件,作为最外层的消息容器,包含头像、气泡等所有元素。
MessageBubbleMessageBubbleRender消息气泡组件,作为消息内容的背景包裹层。
MessageContentMessageContentRender消息内容组件,用于显示具体的消息内容(文本、图片、视频等)。
MessageQuoteBubbleMessageQuoteBubbleRender引用消息气泡组件,用于显示被引用的消息内容。
MessageThreadBubbleMessageThreadRender话题消息气泡组件,用于显示话题相关信息。
MessageReactionMessageReactionRender消息表情回复组件,用于显示消息的表情回复。
SystemTipViewSystemTipViewRender系统提示组件,用于显示系统消息(如"xxx 撤回了一条消息")。
TimeTipViewTimeTipViewRender时间提示组件,用于显示消息时间分隔。
ListItemRenderMessageListItemComponentType完整消息条目组件(替换所有上述组件)。

自定义消息内容

MessageContent 是最常用的自定义组件,用于定义消息内容的显示方式,例如,自定义图片消息的呈现效果,或添加自定义消息类型。

基础用法

import React from 'react';
import { View, Text } from 'react-native';
import {
  MessageContent,
  MessageContentProps,
  ChatMessageType,
  ChatCustomMessageBody,
} from 'react-native-chat-uikit';

// 自定义消息内容组件
export function CustomMessageContent(props: MessageContentProps) {
  const { msg, isSupport } = props;

  // 处理自定义消息类型
  if (msg.body.type === ChatMessageType.CUSTOM) {
    const body = msg.body as ChatCustomMessageBody;

    // 自定义安全提示消息
    if (body.event === 'custom_safe_tip') {
      return (
        <View style={{ padding: 10, backgroundColor: '#FFF3E0', borderRadius: 8 }}>
          <Text style={{ color: '#E65100', fontSize: 14 }}>
            {body.params?.tip || '安全提示'}
          </Text>
        </View>
      );
    }

    // 自定义红包消息
    if (body.event === 'custom_red_packet') {
      return (
        <View style={{
          padding: 15,
          backgroundColor: '#FF5722',
          borderRadius: 8,
          minWidth: 200,
        }}>
          <Text style={{ color: 'white', fontSize: 16, fontWeight: 'bold' }}>
            🧧 {body.params?.title || '恭喜发财,大吉大利'}
          </Text>
          <Text style={{ color: 'white', fontSize: 12, marginTop: 5 }}>
            {body.params?.subtitle || '点击领取红包'}
          </Text>
        </View>
      );
    }
  }

  // 其他类型使用默认渲染
  return <MessageContent {...props} />;
}

// 在 ConversationDetail 中使用
<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      listItemRenderProps: {
        MessageContent: CustomMessageContent,
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

自定义图片消息显示

import React from 'react';
import { View } from 'react-native';
import {
  MessageContent,
  MessageContentProps,
  ChatMessageType,
  DefaultImage,
  getImageShowSize,
  getImageThumbUrl,
} from 'react-native-chat-uikit';
import FastImage from 'react-native-fast-image'; // 使用第三方图片库

export function CustomMessageContent(props: MessageContentProps) {
  const { msg, contentMaxWidth } = props;
  const [thumbUrl, setThumbUrl] = React.useState<string | undefined>();

  // 自定义图片消息的显示
  if (msg.body.type === ChatMessageType.IMAGE) {
    const { width, height } = getImageShowSize(msg, contentMaxWidth);

    React.useEffect(() => {
      getImageThumbUrl(msg)
        .then((url) => setThumbUrl(url))
        .catch((error) => console.error('加载图片失败:', error));
    }, [msg]);

    return (
      <View
        style={{
          width,
          height,
          borderRadius: 12,
          overflow: 'hidden',
          borderWidth: 1,
          borderColor: '#E0E0E0',
        }}
      >
        <FastImage
          source={{ uri: thumbUrl }}
          style={{ width, height }}
          resizeMode={FastImage.resizeMode.cover}
        />
      </View>
    );
  }

  // 其他消息类型使用默认渲染
  return <MessageContent {...props} />;
}

自定义消息视图

MessageView 是消息条目的最外层容器,整合了头像、昵称、消息气泡、状态标识等所有消息元素,是控制消息整体布局的核心入口。

例如,隐藏左侧消息的头像:

import React from 'react';
import { MessageView, MessageViewProps } from 'react-native-chat-uikit';

export function CustomMessageView(props: MessageViewProps) {
   // 左侧消息(接收)隐藏头像
  if (props.model.layoutType === 'left') {
    return <MessageView {...props} avatarIsVisible={false} />;
  }

  // 右侧消息(发送)保持默认
  return <MessageView {...props} />;
}

// 使用自定义组件
<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      listItemRenderProps: {
        MessageView: CustomMessageView,
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

自定义消息气泡

MessageBubble 是包裹消息内容的背景容器组件,负责消息气泡的视觉样式呈现,包括背景色、圆角、阴影等外观属性。详见 消息列表的基本设置说明

自定义消息回复 Reaction

MessageReaction 是用于展示消息 Reaction 的组件,支持用户通过表情对消息进行快捷回复。

自定义系统提示消息

SystemTipView 是系统提示消息的样式组件。你可通过该组件自定义提示消息的字体、颜色、字号等样式属性。

自定义消息时间戳

TimeTipView 是消息时间戳的样式组件。你可通过该组件自定义时间戳的字体、颜色、字号等样式属性。

组合自定义示例

  • 你可以同时自定义多个组件,实现完整的个性化消息样式:
<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      listItemRenderProps: {
        // 自定义消息视图
        MessageView: CustomMessageView,
        // 自定义消息气泡
        MessageBubble: CustomMessageBubble,
        // 自定义消息内容
        MessageContent: CustomMessageContent,
        // 自定义系统提示
        SystemTipView: CustomSystemTipView,
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>
  • 实际项目示例

    以下示例来自 product-uikit-demo,展示了如何自定义图片消息的渲染,使用 FastImage 优化图片加载性能:

// 自定义图片组件,使用 FastImage 优化性能
export function DemoMessageImage(props: MessageImageProps) {
  const { msg, maxWidth } = props;
  const [thumbUrl, setThumbUrl] = React.useState<string | undefined>();
  const { width, height } = getImageShowSize(msg, maxWidth);

  React.useEffect(() => {
    getImageThumbUrl(msg)
      .then((url) => setThumbUrl(url))
      .catch((error) => console.error(error));
  }, [msg]);

  return (
    <DemoMessageDefaultImage
      url={thumbUrl}
      width={width}
      height={height}
      thumbWidth={64}
      thumbHeight={64}
      iconName={'img'}
    />
  );
}

// 自定义消息内容组件
export function DemoMessageContent(props: MessageContentProps) {
  const { msg, isSupport, layoutType, contentMaxWidth, ...others } = props;

  // 处理图片消息
  if (isSupport === true) {
    if (msg.body.type === ChatMessageType.IMAGE) {
      return (
        <DemoMessageImage
          layoutType={layoutType}
          msg={msg}
          maxWidth={contentMaxWidth}
          {...others}
        />
      );
    }
  }

  // 其他消息类型使用默认渲染
  return <MessageContent {...props} />;
}

// 在聊天页面中使用
<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      listItemRenderProps: {
        MessageContent: DemoMessageContent,
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

设置长按消息菜单

在消息列表中长按任意消息,弹出操作菜单。UIKit 提供三种风格的消息长按菜单:底部弹出菜单、类似微信风格菜单和自定义菜单。关于菜单风格的选择,详见 消息列表的基本设置说明

通过 onInitMenu 属性自定义菜单项,包括添加、修改和删除菜单项。

管理菜单项

添加菜单项

每个菜单项均为 InitMenuItemsType 对象,包含以下属性:

属性名类型是否必需描述
namestring菜单项文本。
isHighboolean是否高亮(危险操作)。
iconIconNameType图标名称。
onClicked(name, others?) => void点击回调。
<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      onInitMenu: (initItems) => {
        // 在默认菜单项后面添加自定义菜单项
        return [
          ...initItems,
          {
            name: '收藏',
            isHigh: false,
            icon: 'star',
            onClicked: (name) => {
              console.log('收藏消息:', name);
              // todo: 处理收藏逻辑
            },
          },
          {
            name: '翻译',
            isHigh: false,
            icon: 'globe',
            onClicked: () => {
              // todo: 处理翻译逻辑
            },
          },
        ];
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

修改菜单项

<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      onInitMenu: (initItems) => {
        // 修改"删除"菜单项的文本
        return initItems.map((item) => {
          if (item.name === '删除') {
            return {
              ...item,
              name: '彻底删除',
              isHigh: true, // 设置为高亮
            };
          }
          return item;
        });
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

删除菜单项

<ConversationDetail
  type="chat"
  convId={convId}
  convType={convType}
  list={{
    props: {
      onInitMenu: (initItems) => {
        // 删除"转发"和"多选"菜单项
        return initItems.filter((item) => {
          return item.name !== '转发' && item.name !== '多选';
        });
      },
    },
  }}
  onBack={() => navigation.goBack()}
/>

修改菜单图标

关于修改菜单项的图标,详见 图标自定义文档

使用控制器

通过 MessageListRef 获取控制器,实现高级功能。

MessageListRef 提供以下控制器方法:

方法名参数返回值描述
addSendMessagevalue: SendMessagePropsvoid添加消息到列表底部位置。
addSendMessageToUIparams: {value, onFinished?, onBeforeCallback?}Promise<void>添加消息到 UI,并提供回调。
sendMessageToServermsg: ChatMessagevoid将消息发送到服务器。
saveMessagemsg: ChatMessagevoid将消息保存到本地数据库。
removeMessagemsg: ChatMessagevoid从消息列表中移除消息。
recallMessagemsg: ChatMessagevoid撤回消息。
updateMessageupdatedMsg: ChatMessage, fromType: 'send' | 'recv'void更新消息。
loadHistoryMessagemsgs: ChatMessage[], pos: 'top' | 'bottom'void加载历史消息到指定位置。
onInputHeightChangeheight: numbervoid输入组件高度变化时的回调通知。
editMessageFinishedmodel: MessageModelvoid消息编辑完成时的回调通知。
scrollToBottomvoid滚动列表到底部。
startShowThreadMoreMenuvoid显示话题更多菜单。
cancelMultiSelectedvoid取消多选模式。
removeMultiSelectedonResult: (confirmed: boolean) => voidvoid移除多选的消息。
getMultiSelectedMessagesChatMessage[]获取多选的消息列表。
showPinMessageComponentvoid显示置顶消息组件。
hidePinMessageComponentvoid隐藏置顶消息组件。
requestShowPinMessageComponentonResult: (count: number) => voidvoid请求显示置顶消息组件,可根据置顶消息数量决定是否显示。

添加消息到列表

通过以下两种方式添加消息到列表:

  • 使用控制器的 addSendMessage 方法:
import React, { useRef } from 'react';
import type { MessageListRef } from 'react-native-chat-uikit';

function ChatScreen({ route }) {
  const { convId, convType } = route.params;
  const messageListRef = useRef<MessageListRef>(null);

  const handleAddMessage = () => {
    messageListRef.current?.addSendMessage({
      type: 'text',
      content: 'Hello, World!',
    });
  };

  return (
    <ConversationDetail
      type="chat"
      convId={convId}
      convType={convType}
      list={{
        ref: messageListRef,
      }}
      onBack={() => navigation.goBack()}
    />
  );
}
  • 使用 addSendMessageToUI 方法。该方法提供更多控制选项:
const handleAddMessageWithCallback = async () => {
  await messageListRef.current?.addSendMessageToUI({
    value: {
      type: "text",
      content: "Hello!",
    },
    onBeforeCallback: async () => {
      console.log("添加消息前的准备工作");
    },
    onFinished: (item) => {
      console.log("消息已添加到UI:", item);
    },
  });
};

移除消息

通过控制器的 removeMessage 方法移除消息:

const handleRemoveMessage = (message: ChatMessage) => {
  messageListRef.current?.removeMessage(message);
};

撤回消息

通过控制器的 recallMessage 方法撤回消息:

const handleRecallMessage = (message: ChatMessage) => {
  messageListRef.current?.recallMessage(message);
};

更新消息

通过控制器的 updateMessage 方法更新消息:

const handleUpdateMessage = (updatedMessage: ChatMessage) => {
  messageListRef.current?.updateMessage(updatedMessage, "send");
  // 第二个参数: 'send' 表示发送的消息,'recv' 表示接收的消息
};

滚动控制

通过控制器的 scrollToBottom 方法可滚动到消息列表底部:

const handleScrollToBottom = () => {
  messageListRef.current?.scrollToBottom();
};

多选消息

通过控制器可实现多选消息:

方法描述
cancelMultiSelected取消多选模式。
removeMultiSelected删除选中的消息。
getMultiSelectedMessages获取选中的消息列表。
// 取消多选模式
const handleCancelMultiSelect = () => {
  messageListRef.current?.cancelMultiSelected();
};

// 删除多选的消息
const handleRemoveMultiSelected = () => {
  messageListRef.current?.removeMultiSelected((confirmed) => {
    if (confirmed) {
      console.log("用户确认删除");
    } else {
      console.log("用户取消删除");
    }
  });
};

// 获取多选的消息列表
const handleGetMultiSelected = () => {
  const messages = messageListRef.current?.getMultiSelectedMessages() || [];
  console.log("选中的消息:", messages);
};

置顶消息

通过控制器可以控制置顶消息组件的显示和隐藏(仅群聊支持):

方法描述
showPinMessageComponent显示置顶消息组件。
hidePinMessageComponent隐藏置顶消息组件。
requestShowPinMessageComponent根据置顶数量决定是否显示。
// 显示置顶消息组件
const handleShowPinMessage = () => {
  messageListRef.current?.showPinMessageComponent();
};

// 隐藏置顶消息组件
const handleHidePinMessage = () => {
  messageListRef.current?.hidePinMessageComponent();
};

// 请求显示置顶消息组件(根据置顶消息数量决定是否显示)
const handleRequestShowPinMessage = () => {
  messageListRef.current?.requestShowPinMessageComponent((count) => {
    console.log("置顶消息数量:", count);
    // 可以根据数量决定是否显示
  });
};

自定义事件监听

关于自定义消息列表的事件监听,详见 自定义数据模型文档

自定义资源

上次编辑于: