消息列表的高级设置

大约 33 分钟

消息列表的高级设置

消息列表是聊天界面的核心组件,基于 MessageListControllerMessageListView 实现。本文介绍如何通过配置 AppearanceComponentsRegister 实现消息列表的高级设置。

概述

可通过以下方式定制消息列表:

  • Appearance.chat: 配置 UI 样式、图标、菜单项等。
  • ComponentsRegister: 注册自定义消息条目或替换核心组件类。

提示

  • 所有配置项均可通过 Appearance.chat 全局调整。
  • contentStyle 支持组合使用多个样式,例如 [.withReply, .withAvatar]
  • 图片资源可通过在 Bundle.main 中提供同名文件覆盖。
  • 国际化字符串可通过在 Bundle.mainLocalizable.strings 中提供同名 key 覆盖。

Appearance.chat 消息配置

  • 消息气泡样式
配置项类型默认值说明
bubbleStyleMessageBubbleDisplayStyle.withArrow消息气泡显示样式:带箭头(.withArrow) 或多圆角(.withMultiCorner)
contentStyle[MessageContentDisplayStyle][.withReply, .withAvatar, .withNickName, .withDateAndTime]内容显示组合:回复、头像、昵称、时间等
  • 输入框配置
配置项类型默认值说明
maxInputHeightCGFloat88输入框最大高度限制:MessageInputBar 高度上限
inputPlaceHolderString"Aa"输入框占位符文本:MessageInputBar 提示文字
inputBarCornerCornerRadius.extraSmall输入框圆角样式:MessageInputBar 圆角
  • 消息操作菜单
配置项类型默认值说明
messageLongPressedActions[ActionSheetItemProtocol]12 个操作项长按消息操作菜单:包含复制、转发、话题、回复、撤回、编辑、多选、置顶、翻译、显示原文、举报、删除
messageLongPressMenuStyleMessageLongPressMenuStyle.withArrow消息长按菜单样式:
- 带箭头菜单(.withArrow)
- ActionSheet(.actionSheet)
  • 消息翻译
配置项类型默认值说明
targetLanguageLanguageType.Chinese目标翻译语言
enableTranslationBoolfalse是否启用翻译功能:需从控制台开启后设置为 true
  • 举报功能
配置项类型默认值说明
reportSelectionTags[String]["tag1"..."tag9"]消息举报类型标签
reportSelectionReasons[String]9 个违规原因消息举报原因列表
  • 附件菜单配置
配置项类型默认值说明
inputExtendActions[ActionSheetItemProtocol]4 个操作项点击"+"按钮弹出的菜单项:包含照片、相机、文件、联系人
messageAttachmentMenuStyleMessageAttachmentMenuStyle.followInput附件菜单样式:跟随输入框(.followInput) 或 ActionSheet(.actionSheet)
  • 消息时间格式
配置项类型默认值说明
dateFormatTodayString"HH:mm"当天消息时间格式
dateFormatOtherDayString"yyyy-MM-dd HH:mm"非当天消息时间格式
  • 语音消息配置
配置项类型默认值说明
audioDurationInt60录音时长限制(秒):最长 60 秒
receiveAudioAnimationImages[UIImage]3 张图片接收方音频播放动画图片:左侧音频播放动画帧
sendAudioAnimationImages[UIImage]3 张图片发送方音频播放动画图片: 右侧音频播放动画帧
newMessageSoundPathString系统音效路径新消息提示音路径:收到新消息的提示音
  • 文本颜色配置
配置项类型默认值说明
receiveTextColorUIColor深色模式:neutralColor98
浅色模式:neutralColor1
接收方文本颜色
sendTextColorUIColor深色模式:neutralColor1
浅色模式:neutralColor98
发送方文本颜色
receiveTranslationColorUIColor深色模式:neutralColor7
浅色模式:neutralColor5
接收方翻译文本颜色
sendTranslationColorUIColor深色模式:neutralSpecialColor2
浅色模式:neutralSpecialColor95
发送方翻译文本颜色
  • 图片/视频消息配置
配置项类型默认值说明
imageMessageCornerCGFloat4图片消息圆角大小
imagePlaceHolderUIImage?image_message_placeHolder图片加载占位图
videoPlaceHolderUIImage?video_message_placeHolder视频封面占位图
  • 消息撤回配置
配置项类型默认值说明
recallExpiredTimeUInt120消息撤回时限(秒):消息发送后可撤回的最长时间
  • 群组配置
配置项类型默认值说明
groupParticipantsLimitCountInt1000群成员最大数量
  • 新消息提醒配置
配置项类型默认值说明
moreMessageAlertPositionMoreMessagePosition.center新消息提醒位置:左侧(.left)、居中(.center)、右侧(.right)
  • 输入状态配置
配置项类型默认值说明
enableTypingBooltrue是否显示对方正在输入状态
  • 置顶消息配置
配置项类型默认值说明
enablePinMessageBooltrue是否启用置顶消息功能
  • URL 预览配置
配置项类型默认值说明
titlePreviewPatternString""URL 预览标题正则表达式
descriptionPreviewPatternString""URL 预览描述正则表达式
imagePreviewPatternString""URL 预览图片正则表达式
enableURLPreviewBooltrue是否启用 URL 预览

消息相关枚举类型说明

  • MessageAttachmentMenuStyle:附件菜单样式
说明
.followInput菜单跟随输入框显示(类似微信)
.actionSheet使用 ActionSheet 样式(类似系统菜单)
  • MessageLongPressMenuStyle:长按菜单样式
说明
.withArrow带箭头的菜单(类似微信)
.actionSheet使用 ActionSheet 样式(类似系统菜单)
  • MessageBubbleDisplayStyle:消息气泡显示样式
说明
.withArrow带箭头的气泡样式
.withMultiCorner多圆角气泡样式(无箭头)
  • MessageContentDisplayStyle:消息气泡内容显示样式
说明
.withReply显示回复内容
.withAvatar显示用户头像
.withNickName显示用户昵称
.withDateAndTime显示日期时间
.withMessageThread显示消息话题
.withMessageReaction显示消息表情回应

修改文本消息字体和颜色

需继承 MessageEntity 类并注册到 EaseChatUIKit 中的 ComponentsRegister 中,重载 convertTextAttribute 方法。

import EaseChatUIKit

class MineMessageEntity: MessageEntity {
    override func convertTextAttribute() -> NSAttributedString? {
        //根据具体需求参考或者复制原有逻辑改动相关字体颜色代码
    }
}

设置消息状态图标

消息状态图标包括:正在发送、已发送成功、发送失败、已送达、已读。

自定义图标资源

  • 方式一:(推荐)替换图片资源

在主 Bundle 中添加同名图片文件自动替换:

状态默认图片名称
正在发送message_status_spinner
已发送成功message_status_succeed
发送失败message_status_failure
已送达message_status_delivery
已读message_status_read
  • 方式二:代码动态设置
  1. 继承 MessageEntity,创建自定义子类。
  2. 重写 getStateImage() 方法,返回自定义图标。
  3. 注册自定义类至 ComponentsRegister.shared.MessageEntity
    open func getStateImage() -> UIImage? {
        switch self.state {
        case .sending:
            return UIImage(chatNamed: "message_status_spinner")
        case .succeed:
            return UIImage(chatNamed: "message_status_succeed")
        case .failure:
            return UIImage(chatNamed: "message_status_failure")
        case .delivered:
            return UIImage(chatNamed: "message_status_delivery")
        case .read:
            return UIImage(chatNamed: "message_status_read")
        }
    }
    

隐藏状态图标

若要完全隐藏消息状态图标,请按以下步骤操作:

  1. 继承 MessageCell,创建自定义 MessageCell 子类。
  2. 重写 refresh(entity:) 方法,隐藏 status 视图。
  3. 注册自定义类至 ComponentsRegister
        override func refresh(entity: MessageEntity) {
            super.refresh(entity: entity)
            self.status.isHidden = true //隐藏状态图标
        }

设置长按消息菜单

通过 Appearance.chat.messageLongPressedActions 配置长按菜单项,可添加自定义项或移除默认项。

关于选择微信样式菜单或仿系统 ActionSheet 样式,详见 消息列表的基本设置说明

管理菜单项

// 获取默认菜单项
var actions = Appearance.chat.messageLongPressedActions

// 添加自定义菜单项
let customAction = ActionSheetItem(title: "自定义", type: .normal, tag: "CustomTag", image: UIImage(named: "custom_icon"))
customAction.action = { item, message in
    // 处理点击事件
    print("点击了自定义菜单")
}

// 添加到菜单列表
actions.append(customAction)

// 移除不需要的菜单项
actions.removeAll { $0.tag = "xxx"} 

// 更新配置 
Appearance.chat.messageLongPressedActions = actions

设置菜单样式

  • 图标替换/隐藏:详见 Chat/消息条目的图片和国际化资源表
  • 文字颜色:详见 主题色的说明
  • 修改菜单项文字大小: 菜单样式属于全局统一配置,目前不支持对单个菜单项的文字大小进行单独修改。 若需调整菜单项的文字大小及其相关子视图的尺寸,可通过修改全局字体样式实现。例如,更新 UIFont.theme.labelSmall 来统一控制菜单中对应级别的文字外观:
        UIFont.theme.labelSmall = UIFont.systemFont(ofSize: 12, weight: .medium)

完全自定义消息条目

若要展示自定义类型的消息,或完全重写现有消息的展示样式,可通过 ComponentsRegister 注册自定义消息条目(Cell)。

本节以红包消息为例,介绍如何添加新类型消息条目。

步骤一 继承自定义消息条目

根据需求继承 EaseChatUIKit 中的自定义消息条目。

import UIKit
import EaseChatUIKit

class RedPackageCell: CustomMessageCell {

    override func createContent() -> UIView {
        UIView(frame: self.contentView.bounds).backgroundColor(.clear).tag(bubbleTag).backgroundColor(.systemRed)
    }
    
    override func refresh(entity: MessageEntity) {
        super.refresh(entity: entity)
    }
            
         // 自定义气泡箭头颜色
        override func updateAxis(entity: MessageEntity) {
        super.updateAxis(entity: entity)
        if Appearance.chat.bubbleStyle == .withArrow {
            self.bubbleWithArrow.arrow.image = UIImage(named: self.towards == .left ? "arrow_left": "arrow_right", in: .chatBundle, with: nil)?.withTintColor(self.towards == .left ? .systemRed:.systemRed)
        } else {
            self.bubbleMultiCorners.backgroundColor = .systemRed
        }
    }
}

步骤二 继承消息条目的渲染模型

根据需求继承 MessageEntity(消息条目的渲染模型),重写 customSize() 方法指定气泡尺寸。其中 redPackageIdentifier 为红包的自定义消息的 event 标识。

import UIKit
import EaseChatUIKit

final class MineMessageEntity: MessageEntity {
    
    override func customSize() -> CGSize {
        if let body = self.message.body as? ChatCustomMessageBody {
            switch body.event {
            case EaseChatUIKit_user_card_message:
                return CGSize(width: self.historyMessage ? ScreenWidth-32:limitBubbleWidth, height: contactCardHeight)
            case EaseChatUIKit_alert_message:
                let label = UILabel().numberOfLines(0).lineBreakMode(.byWordWrapping)
                label.attributedText = self.convertTextAttribute()
                let size = label.sizeThatFits(CGSize(width: ScreenWidth-32, height: 9999))
                return CGSize(width: ScreenWidth-32, height: size.height+50)
            case redPackageIdentifier:
                return CGSize(width: limitBubbleWidth, height: limitBubbleWidth*(5/3.0))
            default:
                return .zero
            }
            
        } else {
            return .zero
        }
    }

    
}

步骤三 添加附件消息类型

添加附件消息的类型,例如,增加红包消息。

        
        let redPackage = ActionSheetItem(title: "红包".chat.localize, type: .normal,tag: "Red",image: UIImage(named: "photo", in: .chatBundle, with: nil))
        Appearance.chat.inputExtendActions.append(redPackage)

步骤四 处理附件消息点击

继承 MessageListController,处理新增附件消息类型的点击事件。

class CustomMessageListController: MessageListController {
    
    override func handleAttachmentAction(item: any ActionSheetItemProtocol) {
        switch item.tag {
        case "File": self.selectFile()
        case "Photo": self.selectPhoto()
        case "Camera": self.openCamera()
        case "Contact": self.selectContact()
        case "Red": self.redPackageMessage()
        default:
            break
        }
    }
    
    private func redPackageMessage() {
        self.viewModel.sendRedPackageMessage()
    }

}

let redPackageIdentifier = "redPackage"

步骤五 增加发送方法

EaseChatUIKitMessageListViewModel 中增加发送红包消息的方法。

extension MessageListViewModel {
    func sendRedPackageMessage() {
        var ext = Dictionary<String,Any>()
        ext["something"] = "发红包"
        let json = ChatUIKitContext.shared?.currentUser?.toJsonObject() ?? [:]
        ext.merge(json) { _, new in
            new
        }
        let chatMessage = ChatMessage(conversationID: self.to, body: ChatCustomMessageBody(event: redPackageIdentifier, customExt: ["money": "20", "name": "张三","message": "恭喜发财大吉大利"]), ext: ext)
        self.driver?.showMessage(message: chatMessage)
        self.chatService?.send(message: chatMessage) { [weak self] error, message in
            if error == nil {
                if let message = message {
                    self?.driver?.updateMessageStatus(message: message, status: .succeed)
                }
            } else {
                consoleLogInfo("send text message failure:\(error?.errorDescription ?? "")", type: .error)
                if let message = message {
                    self?.driver?.updateMessageStatus(message: message, status: .failure)
                }
            }
        }
    }
    
    
}

步骤六 注册继承的对象

将继承的对象初始化后注册在 EaseChatUIKit 中。

        
        ComponentsRegister.shared.MessageRenderEntity = MineMessageEntity.self
        ComponentsRegister.shared.Conversation = MineConversationInfo.self
        ComponentsRegister.shared.MessageViewController = CustomMessageListController.self
        //redPackageIdentifier 为消息条目的唯一标识,也是环信自定义消息的时间类型
        ComponentsRegister.shared.registerCustomCellClasses(cellType: RedPackageCell.self,identifier: redPackageIdentifier)

其中 ComponentsRegister.shared.Conversation = MineConversationInfo.self 用于在会话列表中自定义新消息的展示内容。例如,收到红包消息时显示为 "[红包]"。通过在 else 分支中根据消息的 event 类型返回对应文本实现:

import UIKit
import EaseChatUIKit


final class MineConversationInfo: ConversationInfo {
    
    override func contentAttribute() -> NSAttributedString {
        guard let message = self.lastMessage else { return NSAttributedString() }
        var text = NSMutableAttributedString()
        
        let from = message.from
        let mentionText = "Mentioned".chat.localize
        let user = ChatUIKitContext.shared?.userCache?[from]
        var nickName = user?.remark ?? ""
        if nickName.isEmpty {
            nickName = user?.nickname ?? ""
        }
        if nickName.isEmpty {
            nickName = from
        }
        if message.body.type == .text {
            var result = message.showType
            for (key,value) in ChatEmojiConvertor.shared.oldEmojis {
                result = result.replacingOccurrences(of: key, with: value)
            }
            text.append(NSAttributedString {
                AttributedText(result).foregroundColor(Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5).font(UIFont.theme.bodyLarge)
            })
            let string = text.string as NSString
            for symbol in ChatEmojiConvertor.shared.emojis {
                if string.range(of: symbol).location != NSNotFound {
                    let ranges = text.string.chat.rangesOfString(symbol)
                    text = ChatEmojiConvertor.shared.convertEmoji(input: text, ranges: ranges, symbol: symbol,imageBounds: CGRect(x: 0, y: -3, width: 16, height: 16))
                    text.addAttribute(.font, value: UIFont.theme.bodyLarge, range: NSMakeRange(0, text.length))
                    text.addAttribute(.foregroundColor, value: Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5, range: NSMakeRange(0, text.length))
                }
            }
            if self.mentioned {
                let showText = NSMutableAttributedString {
                    AttributedText("[\(mentionText)] ").foregroundColor(Theme.style == .dark ? UIColor.theme.primaryColor6:UIColor.theme.primaryColor5).font(Font.theme.bodyMedium)
                    AttributedText(nickName + ": ").foregroundColor(Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5)
                }
                
                let show = NSMutableAttributedString(attributedString: text)
                show.addAttribute(.foregroundColor, value: Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5, range: NSRange(location: 0, length: show.length))
                show.addAttribute(.font, value: UIFont.theme.bodyMedium, range: NSRange(location: 0, length: show.length))
                showText.append(show)
                return showText
            } else {
                let showText = NSMutableAttributedString {
                    AttributedText(message.chatType != .chat ? nickName + ": ":"").foregroundColor(Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5).font(Font.theme.bodyMedium)
                }
                showText.append(text)
                showText.addAttribute(.foregroundColor, value: Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor6, range: NSRange(location: 0, length: showText.length))
                showText.addAttribute(.font, value: UIFont.theme.bodyMedium, range: NSRange(location: 0, length: showText.length))
                return showText
            }
        } else {
            var content = message.showContent
            if let body = message.body as? ChatCustomMessageBody,body.event == redPackageIdentifier {
                content = "[红包]"
            }
            let showText = NSMutableAttributedString {
                AttributedText((message.chatType == .chat ? content:(nickName+":"+content))).foregroundColor(Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5).font(UIFont.theme.bodyMedium)
            }
            return showText
        }
    }

}

步骤七 注册消息条目

// 替换默认的文本消息条目
ComponentsRegister.shared.ChatTextMessageCell = MyCustomMessageCell.self

// 对应的 `ChatImageMessageCell`&`ChatGIFMessageCell`&`ChatAudioMessageCell`&`ChatVideoMessageCell`&`ChatFileMessageCell`&`ChatContactMessageCell`&`ChatAlertCell`&`ChatLocationCell`&`ChatCombineCell` 与文本消息一致
// 或者注册全新的自定义消息类型 Cell
// 假设你有一个自定义消息类型,Identifier 为 "CustomEvent"
ComponentsRegister.shared.registerCustomCellClasses(cellType: MyCustomMessageCell.self, identifier: "CustomEvent")

消息条目业务方法信息及重载

方法列表

方法说明如下:

  1. @objc 标记:方法可被 Objective-C 调用。
  2. open 关键字:方法可在子类中重载。
  3. createXXX() 系列:方法用于创建自定义 UI 组件。
  4. refresh() 方法:用于更新消息条目显示内容。
  5. switchTheme() 方法:用于适配主题切换。

提示

lazy var 属性会在首次访问时才会调用对应方法。

1. MessageCell (基础消息条目)

  • UI 组件创建方法
方法名方法签名说明返回类型参数说明
createCheckbox()@objc open func createCheckbox() -> UIImageView创建多选框图标UIImageView无参数
createAvatar()@objc open func createAvatar() -> ImageView创建头像视图ImageView无参数
createNickName()@objc open func createNickName() -> UILabel创建昵称标签UILabel无参数
createReplyContent()@objc open func createReplyContent() -> MessageReplyView创建回复内容视图MessageReplyView无参数
createBubbleWithArrow()@objc open func createBubbleWithArrow() -> MessageBubbleWithArrow创建带箭头的气泡MessageBubbleWithArrow无参数
createBubbleMultiCorners()@objc open func createBubbleMultiCorners() -> MessageBubbleMultiCorner创建多圆角气泡MessageBubbleMultiCorner无参数
statusView()@objc open func statusView() -> UIImageView创建状态图标视图UIImageView无参数
createMessageDate()@objc open func createMessageDate() -> UILabel创建消息时间标签UILabel无参数
createTopicView()@objc open func createTopicView() -> MessageTopicView创建话题视图MessageTopicView无参数
createReactionView()@objc open func createReactionView() -> MessageReactionView创建表情回应视图MessageReactionView无参数
  • 核心方法
方法名方法签名说明返回类型参数说明
refresh(entity:)@objc(refreshWithEntity:) open func refresh(entity: MessageEntity)刷新消息条目数据显示Voidentity: 消息实体对象
updateAxis(entity:)@objc(updateAxisWithEntity:) open func updateAxis(entity: MessageEntity)更新子视图布局坐标Voidentity: 消息实体对象
clickAction(gesture:)@objc open func clickAction(gesture: UITapGestureRecognizer)处理点击手势Voidgesture: 点击手势识别器
longPressAction(gesture:)@objc open func longPressAction(gesture: UILongPressGestureRecognizer)处理长按手势Voidgesture: 长按手势识别器
switchTheme(style:)open func switchTheme(style: ThemeStyle)切换主题样式Voidstyle: 主题样式枚举

2. TextMessageCell (文本消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> LinkRecognizeTextView创建文本内容视图LinkRecognizeTextView无参数,支持链接识别
createEditSymbol()@objc open func createEditSymbol() -> UIButton创建编辑标识按钮UIButton显示 "Edited" 标记
createTranslationContainer()@objc open func createTranslationContainer() -> TranslateTextView创建翻译容器视图TranslateTextView无参数
createTranslation()@objc open func createTranslation() -> UILabel创建翻译内容标签UILabel无参数
createTranslateSymbol()@objc open func createTranslateSymbol() -> UIButton创建翻译标识按钮UIButton显示 "Translated" 标记
createPreviewContent()@objc open func createPreviewContent() -> URLPreviewResultView创建 URL 预览视图URLPreviewResultView用于链接预览
refresh(entity:)open override func refresh(entity: MessageEntity)刷新文本消息显示Void包含编辑、翻译、URL 预览逻辑
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void调用 onThemeChanged()
onThemeChanged()open func onThemeChanged()主题变化时更新 UIVoid处理链接颜色、选中颜色等

3. ImageMessageCell (图片消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> ImageView创建图片内容视图ImageView带圆角的图片视图
refresh(entity:)open override func refresh(entity: MessageEntity)刷新图片消息显示Void处理本地/远程图片加载
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void更新背景色和边框

4. VideoMessageCell (视频消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> ImageView创建视频封面视图ImageView显示视频缩略图
createPlay()@objc open func createPlay() -> UIImageView创建播放按钮图标UIImageView居中显示的播放图标
refresh(entity:)open override func refresh(entity: MessageEntity)刷新视频消息显示Void加载视频缩略图、控制播放按钮的显示和隐藏
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void更新背景色和边框

5. AudioMessageCell (语音消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> UIView创建语音内容视图UIView返回 AudioMessageView 实例
refresh(entity:)open override func refresh(entity: MessageEntity)刷新语音消息显示Void显示已读/未读红点
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void更新红点颜色

6. FileMessageCell (文件消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> UIView创建文件内容视图UIView返回FileMessageView 实例
refresh(entity:)public override func refresh(entity: MessageEntity)刷新文件消息显示Void调用 FileMessageViewrefresh

7. LocationMessageCell (位置消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> UIView创建位置内容视图UIView空白视图,需自定义实现
refresh(entity:)open override func refresh(entity: MessageEntity)刷新位置消息显示Void包含收发消息 UI 区分
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void空实现,可自定义

8. CustomMessageCell (自定义消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> UIView创建自定义内容视图UIView空白视图,需自定义实现
refresh(entity:)open override func refresh(entity: MessageEntity)刷新自定义消息显示Void包含收发消息 UI 区分
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void空实现,可自定义

9. ContactCardCell (联系人卡片条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> UIView创建联系人卡片视图UIView返回 ContactCardView 实例
refresh(entity:)open override func refresh(entity: MessageEntity)刷新联系人卡片显示Void调用 ContactCardViewrefresh

10. CombineMessageCell (合并消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> CombineMessageView创建合并消息视图CombineMessageView显示聊天记录摘要
refresh(entity:)open override func refresh(entity: MessageEntity)刷新合并消息显示Void调用 CombineMessageViewrefresh
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void空实现,可自定义

11. GIFMessageCell (GIF 消息条目)

方法名方法签名说明返回类型参数说明
createContent()@objc open func createContent() -> GIFAnimatedImageView创建 GIF 动画视图GIFAnimatedImageView支持 GIF 动画播放
refresh(entity:)open override func refresh(entity: MessageEntity)刷新 GIF 消息显示Void加载并播放 GIF 动画
switchTheme(style:)open override func switchTheme(style: ThemeStyle)切换主题Void更新背景色和边框

12. AlertMessageCell (提醒消息)

方法名方法签名说明返回类型参数说明
clickAction(gesture:)open override func clickAction(gesture: UITapGestureRecognizer)处理点击手势Void仅当有 threadId 时响应
refresh(entity:)open override func refresh(entity: MessageEntity)刷新提醒消息显示Void显示时间和提醒内容
switchTheme(style:)public override func switchTheme(style: ThemeStyle)切换主题Void更新时间文字颜色

13. ChatHistoryCell (聊天历史)

方法名方法签名说明返回类型参数说明
refresh(entity:)@objc open func refresh(entity: MessageEntity)刷新聊天历史显示Void支持图片、视频、文本消息显示
switchTheme(style:)public func switchTheme(style: ThemeStyle)切换主题Void更新昵称、分隔线、日期颜色

14. ChatThreadCell (话题)

方法名方法签名说明返回类型参数说明
refresh(chatThread:)open func refresh(chatThread: EaseChatThread)刷新话题信息显示VoidchatThread: 话题对象
renderMessageContent(message:)open func renderMessageContent(message: ChatMessage?) -> NSAttributedString渲染消息内容NSAttributedStringmessage: 最新消息对象
switchTheme(style:)public func switchTheme(style: ThemeStyle)切换主题Void更新各元素颜色

15. PinnedMessageCell (置顶消息)

方法名方法签名说明返回类型参数说明
refresh(entity:)@objc open func refresh(entity: PinnedMessageEntity)刷新置顶消息显示Voidentity: 置顶消息实体
removeAction()@objc open func removeAction()移除按钮点击Void显示确认移除按钮
confirmRemoveAction()@objc open func confirmRemoveAction()确认移除按钮点击Void触发移除回调
switchTheme(style:)public func switchTheme(style: ThemeStyle)切换主题Void更新容器和按钮颜色

16. ForwardTargetCell (转发目标条目)

方法名方法签名说明返回类型参数说明
refresh(info:keyword:forward:)open func refresh(info: ChatUserProfileProtocol, keyword: String, forward state: ForwardTargetState)刷新转发目标显示Voidinfo: 用户信息
keyword: 搜索关键词
state: 转发状态
highlightKeywords(keyword:in:)func highlightKeywords(keyword: String, in string: String) -> NSAttributedString高亮关键词NSAttributedString搜索结果关键词高亮
actionClick()@objc open func actionClick()发送按钮点击Void触发转发回调

17. ReactionDetailCell (表情回应详情)

方法名方法签名说明返回类型参数说明
refresh(reaction:)@objc open func refresh(reaction: MessageReaction)刷新表情回应显示Voidreaction: 表情回应对象

18. ReactionUserCell (表情回应用户)

方法名方法签名说明返回类型参数说明
createCheckbox()@objc open func createCheckbox() -> UIImageView创建多选框UIImageView无参数
createAvatar()@objc open func createAvatar() -> ImageView创建头像视图ImageView无参数
createNickName()@objc open func createNickName() -> UILabel创建昵称标签UILabel无参数
refresh(profile:)@objc open func refresh(profile: ChatUserProfileProtocol)刷新用户信息显示Voidprofile: 用户信息对象

19. ReportOptionCell (举报选项)

方法名方法签名说明返回类型参数说明
refresh(select:title:)@objc open func refresh(select: Bool, title: String)刷新举报选项显示Voidselect: 是否选中
title: 选项标题
switchTheme(style:)open func switchTheme(style: ThemeStyle)切换主题Void更新选中/未选中图标颜色

20. SearchHistoryMessageCell (搜索历史消息)

方法名方法签名说明返回类型参数说明
refresh(message:info:keyword:)func refresh(message: ChatMessage, info: ChatUserProfileProtocol, keyword: String)刷新搜索结果显示Voidmessage: 消息对象
info: 用户信息
keyword: 搜索关键词
highlightKeywords(keyword:in:)func highlightKeywords(keyword: String, in string: String) -> NSAttributedString高亮关键词NSAttributedString搜索结果关键词高亮
switchTheme(style:)public func switchTheme(style: ThemeStyle)切换主题Void更新会话名称颜色

21. MessageEntity 消息模型实例

  • 尺寸计算相关方法

重载尺寸计算方法时避免重复计算。

方法名方法签名返回类型参数说明作用描述
cellHeight()open func cellHeight() -> CGFloatCGFloat无参数计算消息条目的总高度
包含:昵称、回复、气泡、时间、话题、表情回应高度
reactionMenuWidth()open func reactionMenuWidth() -> CGFloatCGFloat无参数计算表情回应区域的宽度
返回可见表情回应的总宽度,超出最大宽度时截断
topicContentHeight()open func topicContentHeight() -> CGFloatCGFloat无参数计算话题内容区域的高度
如果消息包含 Thread 话题,返回topicHeight(58),否则返回 0
reactionContentHeight()open func reactionContentHeight() -> CGFloatCGFloat无参数计算表情回应内容的高度
如果有表情回应,返回reactionHeight(30),否则返回 0
updateBubbleSize()open func updateBubbleSize() -> CGSizeCGSize无参数根据消息类型计算气泡尺寸
支持文本、图片、语音、视频、文件、位置、合并、自定义消息
textSize()open func textSize() -> CGSizeCGSize无参数计算文本消息内容的尺寸
考虑文本属性、换行、emoji 等因素
textBubbleSize()open func textBubbleSize() -> CGSizeCGSize无参数计算文本消息气泡的尺寸
包含文本、编辑标记、翻译、URL 预览的总尺寸
urlPreviewHeight()@objc open func urlPreviewHeight() -> CGFloatCGFloat无参数计算URL预览区域的高度
包含图片、标题、描述的高度,未加载时返回38
translationSize()open func translationSize() -> CGSizeCGSize无参数计算翻译内容的尺寸
如果显示翻译,计算翻译文本的实际尺寸
thumbnailSize(video:)open func thumbnailSize(video: Bool) -> CGSizeCGSizevideo: 是否为视频消息计算图片/视频缩略图尺寸
根据原图宽高比计算适配后的显示尺寸
audioSize()open func audioSize() -> CGSizeCGSize无参数计算语音消息气泡尺寸
根据语音时长返回不同宽度(75-limitBubbleWidth)
customSize()open func customSize() -> CGSizeCGSize无参数计算自定义消息尺寸
支持联系人卡片、提醒消息等自定义类型
updateReplySize()open func updateReplySize() -> CGSizeCGSize无参数计算回复消息气泡的尺寸
包含回复标题和内容的尺寸
  • 内容转换相关方法
方法名方法签名返回类型参数说明作用描述
getStateImage()open func getStateImage() -> UIImage?UIImage?无参数获取消息状态图标
返回:发送中、成功、失败、送达、已读的图标
convertTextAttribute()open func convertTextAttribute() -> NSAttributedString?NSAttributedString?无参数转换文本为富文本属性字符串
处理:文本颜色、emoji、@提醒、链接检测等
convertTopicContent()open func convertTopicContent() -> NSAttributedString?NSAttributedString?无参数转换话题内容为富文本
显示 Thread 话题的最新消息内容
convertTextTranslationAttribute()open func convertTextTranslationAttribute() -> NSAttributedString?NSAttributedString?无参数转换翻译文本为富文本属性字符串
应用翻译文本的颜色和字体样式
convertReplyTitle()open func convertReplyTitle() -> NSAttributedString?NSAttributedString?无参数转换回复消息的标题
显示被回复用户的昵称或 "message doesn't exist"
convertToReply()open func convertToReply() -> NSAttributedString?NSAttributedString?无参数转换回复消息内容为富文本
根据消息类型显示不同的回复预览(文本、图片、语音等)
  • URL 预览相关方法
方法名方法签名返回类型参数说明作用描述
previewStart()open func previewStart()Void无参数启动 URL 预览解析
异步加载链接的标题、描述、图片,完成后更新气泡尺寸

使用示例

自定义尺寸计算

// 示例 1: 自定义消息高度计算
class MyMessageEntity: MessageEntity {
    override func cellHeight() -> CGFloat {
        var height = super.cellHeight()
        // 添加自定义高度
        height += 20
        return height
    }
}

// 示例 2: 自定义文本属性转换
class MyMessageEntity: MessageEntity {
    override func convertTextAttribute() -> NSAttributedString? {
        guard let attributedText = super.convertTextAttribute() else {
            return nil
        }
        // 添加自定义样式
        let mutableText = NSMutableAttributedString(attributedString: attributedText)
        mutableText.addAttribute(.kern, value: 1.5, range: NSRange(location: 0, length: mutableText.length))
        return mutableText
    }
}

// 示例 3: 自定义气泡尺寸
class MyMessageEntity: MessageEntity {
    override func updateBubbleSize() -> CGSize {
        var size = super.updateBubbleSize()
        // 为所有消息增加padding
        size.width += 20
        size.height += 10
        return size
    }
}

// 示例 4: 自定义消息类型显示
extension ChatMessage {
    open override var showType: String {
        if self.body.type == .custom {
            if let body = self.body as? ChatCustomMessageBody {
                if body.event == "my_custom_type" {
                    return "[自定义消息]"
                }
            }
        }
        return super.showType
    }
}

// 示例 5: 自定义自定义消息尺寸
class MyMessageEntity: MessageEntity {
    override func customSize() -> CGSize {
        if let body = self.message.body as? ChatCustomMessageBody {
            switch body.event {
            case "my_order_card":
                return CGSize(width: limitBubbleWidth, height: 150)
            case "my_product_card":
                return CGSize(width: limitBubbleWidth, height: 180)
            default:
                return super.customSize()
            }
        }
        return super.customSize()
    }
}

自定义各消息类型条目

// 示例1: 自定义文本消息条目的内容视图
class MyTextMessageCell: TextMessageCell {
    override func createContent() -> LinkRecognizeTextView {
        let textView = super.createContent()
        textView.font = UIFont.systemFont(ofSize: 16)
        return textView
    }
}

// 示例2: 自定义图片消息条目的刷新逻辑
class MyImageMessageCell: ImageMessageCell {
    override func refresh(entity: MessageEntity) {
        super.refresh(entity: entity)
        // 添加自定义水印
        self.content.layer.borderWidth = 2
        self.content.layer.borderColor = UIColor.red.cgColor
    }
}

// 示例3: 完全自定义消息条目
class OrderMessageCell: CustomMessageCell {
    override func createContent() -> UIView {
        // 创建订单卡片视图
        let orderView = OrderCardView(frame: .zero)
        return orderView
    }
    
    override func refresh(entity: MessageEntity) {
        super.refresh(entity: entity)
        // 解析订单数据并显示
        if let orderData = parseOrderData(entity.message) {
            (self.content as? OrderCardView)?.showOrder(orderData)
        }
    }
}

ChatMessage 扩展中可重载方法

方法名方法签名返回类型作用描述
showDate@objc open var showDate: String { get }String获取会话列表中显示的日期
当天:HH:mm;非当天:yyyy-MM-dd HH:mm
showDetailDate@objc open var showDetailDate: String { get }String获取聊天消息条目中显示的详细日期
格式同 showDate,可单独配置
showType@objc open var showType: String { get }String获取消息类型的显示文本
返回:[图片]、[语音]、[视频]、[文件]、[位置]等本地化文本
replyIcon@objc open var replyIcon: UIImage? { get }UIImage?获取回复消息的图标
根据消息类型返回对应图标(图片、语音、视频、文件等)
showContent@objc open var showContent: String { get }String获取消息显示内容
文本:消息内容;语音:时长;文件:文件名;自定义:自定义内容
contentSize@objc open var contentSize: CGSize { get }CGSize获取自定义消息的内容尺寸
返回自定义消息类型的默认尺寸

使用示例如下:

// 自定义消息类型显示
extension ChatMessage {
  open override var showType: String {if self.body.type == .custom {if let body = self.body as? ChatCustomMessageBody {if body.event == "my_custom_type" {return "[自定义消息]"}}}return super.showType
  }
}

替换核心组件

  1. 如需深度定制消息列表的逻辑(如 ViewModel 或 Controller),可通过替换注册表中的类实现:
// 替换消息列表 ViewModel
ComponentsRegister.shared.MessagesViewModel = MyMessageListViewModel.self

// 替换消息列表 Controller
ComponentsRegister.shared.MessageViewController = MyMessageListController.self
  1. 如需替换 MessageListView,可在继承 MessageListController 后重写 createMessageContainer() 方法,返回自定义的 MessageListView 实例。需确保自定义视图正确实现 IMessageListViewDriver 协议中的方法,并处理好键盘交互、UI 交互及事件分发。

业务逻辑重载

本节所列方法均声明为 open,可在子类中重写以实现自定义逻辑:

override open func methodName(parameters) -> ReturnType {
    // 自定义实现
    super.methodName(parameters) // 可选:调用父类实现
}

MessageListController

方法名作用参数说明
createNavigation()创建并返回导航栏返回 ChatNavigationBar 实例
rightImages()定义导航栏右侧图标返回图标数组(话题、置顶消息)
createMessageContainer()创建消息列表容器视图返回 MessageListView 实例
createLoading()创建加载视图返回 LoadingView 实例
processFollowInputAttachmentAction()处理输入框附件按钮跟随样式的行为配置附件菜单项的点击事件
setupNavigation()设置导航栏的标题、头像等信息根据用户资料配置导航栏
showPinnedMessages()显示置顶消息列表加载并展示置顶消息容器
navigationClick(type:indexPath:)处理导航栏点击事件type: 事件类型, indexPath: 索引路径
viewDetail()查看聊天详情(联系人/群组信息)根据聊天类型跳转到详情页
rightItemsAction(indexPath:)处理导航栏右侧按钮点击indexPath: 按钮索引
viewTopicList()查看话题列表跳转到话题列表页面
pop()返回上一页执行页面返回操作
otherPartyTypingText()对方正在输入提示显示输入状态提示
performTypingTask()执行输入状态任务清除输入状态提示
forwardMessages(messages:)转发多条消息(合并转发)messages: 要转发的消息数组
forwardMessage(message:)转发单条消息message: 要转发的消息
deleteMessages(messages:)删除多条消息messages: 要删除的消息数组
filterSelectedMessages()过滤已选中的消息返回选中的消息数组
enterTopic(threadId:message:)进入话题详情threadId: 话题 ID, message: 消息对象
messageWillSendFillExtensionInfo()消息发送前填充扩展信息返回扩展信息字典
filterMessageActions(message:)过滤消息长按菜单项message: 消息实体,返回可用的菜单项
showMessageLongPressedDialog(cell:)显示消息长按对话框cell: 消息条目
showMessageLongPressedMenuWithArrow(cell:items:header:)显示带箭头的长按菜单cell: 消息条目, items: 菜单项, header: 头部视图
showMessageLongPressedMenuActionSheet(cell:items:header:)显示 ActionSheet 样式的长按菜单cell: 消息条目, items: 菜单项, header: 头部视图
feedback(with:)触觉反馈style: 反馈样式
showAllReactionsController(message:)显示所有表情回应选择器message: 消息实体
showReactionDetailsController(message:)显示表情回应详情message: 消息实体
processMessage(item:message:)处理消息操作item: 操作项, message: 消息对象
multiSelect(message:)进入多选模式message: 初始选中的消息
toCreateThread(message:)创建话题message: 关联的消息
editAction(message:)编辑消息message: 要编辑的消息
reportAction(message:)举报消息message: 要举报的消息
messageAttachmentLoading(loading:)消息附件加载状态loading: 是否正在加载
messageBubbleClicked(message:)消息气泡点击事件message: 消息实体
viewHistoryMessages(entity:)查看历史消息entity: 合并消息实体
viewAlertDetail(message:)查看提醒消息详情message: 提醒消息
viewContact(body:)查看联系人名片body: 自定义消息体
messageAvatarClick(user:)消息头像点击user: 用户资料
audioDialog()显示录音对话框弹出录音视图
mentionAction()@提及功能选择要@的成员
attachmentDialog()显示附件菜单弹出附件选择菜单
handleAttachmentAction(item:)处理附件操作item: 附件操作项
selectPhotoWithPHPicker()使用 PHPicker 选择照片打开系统相册
selectPhoto()选择照片(旧API)使用 UIImagePickerController
openCamera()打开相机拍照或录像
selectFile()选择文件打开文件选择器
selectContact()选择联系人分享联系人名片
openFile()打开文件预览使用 QuickLook 预览
processImagePickerData(info:)处理图片选择器数据info: 选择的媒体信息
documentPickerOpenFile(controller:urls:)处理文档选择器结果controller: 选择器, urls: 文件 URLs

MessageListView

方法名作用参数说明
refreshPreviewResult(entity:)刷新 URL 预览结果entity: 消息实体
scrollToBottom()滚动到底部平滑滚动到消息列表底部

提示

MessageListView 作为视图类,主要提供协议方法的实现,可复写的 open 方法较少。大部分逻辑通过实现 IMessageListViewDriver 协议定义,由内部调用,通常无需直接复写。

MessageListViewModel

方法名作用参数说明
bindDriver(driver:searchMessageId:)绑定视图驱动器driver: 视图驱动, searchMessageId: 搜索消息ID
bindPinContainerDriver(driver:)绑定置顶消息容器驱动器driver: 置顶容器驱动
loadSearchMessage()加载搜索消息根据消息ID加载上下文消息
loadMessages()加载历史消息下拉加载更多消息
sendMessage(text:type:extensionInfo:)发送消息text: 消息内容/路径, type: 消息类型, extensionInfo: 扩展信息
constructMessage(text:type:extensionInfo:)构造消息对象text: 消息内容, type: 消息类型, extensionInfo: 扩展信息
updateMentionIds(profile:type:)更新@提及列表profile: 用户资料, type: 添加/删除
processMessage(operation:message:edit:)处理消息操作operation: 操作类型, message: 消息, edit: 编辑文本
fetchPinnedMessages()获取置顶消息从服务器获取置顶消息列表
showPinnedMessages()显示置顶消息返回置顶消息实体数组
pin(message:)置顶消息message: 要置顶的消息
pinAlert(info:operation:)置顶提醒消息info: 置顶信息, operation: 置顶/取消置顶
translateMessage(message:)翻译消息message: 要翻译的消息
showOriginalText(message:)显示原文message: 消息对象
editMessage(message:content:)编辑消息message: 消息, content: 新内容
copyMessage(message:)复制消息message: 要复制的消息
replyMessage(message:)回复消息message: 要回复的消息
recallMessage(message:)撤回消息message: 要撤回的消息
recallAction(message:)撤回动作处理message: 被撤回的消息
deleteMessage(message:)删除消息message: 要删除的消息
deleteMessages(messages:)删除多条消息messages: 要删除的消息数组
notifyUnreadCountChanged()通知未读数变化发送未读数变化通知
messageTopicClicked(entity:)消息话题点击entity: 消息实体
messageReactionClicked(reaction:entity:)消息表情回应点击reaction: 回应表情, entity: 消息实体
operationReaction(emoji:message:)操作表情回应emoji: 表情, message: 消息
messageVisibleMark(entity:)消息可见标记entity: 可见的消息实体
retrySendMessage(entity:)重试发送消息entity: 发送失败的消息
onMessageBubbleClicked(message:)消息气泡点击处理message: 消息实体
audioMessagePlay(message:)音频消息播放message: 音频消息实体
downloadMessageAttachment(message:)下载消息附件message: 消息实体
cacheImage(message:)缓存图片message: 图片消息
cacheFrame(attachMessage:)缓存视频帧attachMessage: 视频消息
messageAvatarLongPressed(profile:)消息头像长按profile: 用户资料
processInputEvents(action:attributeText:)处理输入事件action: 输入动作, attributeText: 富文本
notifyTypingState()通知输入状态发送正在输入的通知
willSendMessage(attributeText:)即将发送消息attributeText: 输入的富文本
messageDidReceived(message:)收到消息message: 接收到的消息
messageDidRecalled(recallInfo:)消息被撤回recallInfo: 撤回信息
messageDidEdited(message:)消息被编辑message: 编辑后的消息
messageStatusChanged(message:status:error:)消息状态变化message: 消息, status: 状态, error: 错误
messageAttachmentStatusChanged(message:error:)附件状态变化message: 消息, error: 错误
messageReactionChanged(changes:)表情回应变化changes: 变化数组

自定义资源

Bundle.main 中添加同名资源即可覆盖默认资源:

  • 图片资源:通过 UIImage(chatNamed:) 加载,在 Bundle.main 中放置同名文件即可覆盖。
  • 国际化资源:通过 .chat.localize 扩展加载,在 Bundle.main 的对应语言目录的 Localizable.strings 中添加相同 key 的翻译即可覆盖。
  • 主题适配:图片会根据当前系统模式自动渲染(如 audio_message_icon_show_left/audio_message_icon_show_right 在亮色/暗色模式下显示不同颜色),无需提供两套资源。如需修改颜色,可调整 Appearance 中的 hue 值(如 Appearance.neutralHueAppearance.neutralSpecialHue),或在组件的 ThemeSwitchProtocol 扩展中自定义。

AudioMessageView 为例,图片会根据系统模式自动适配颜色:

              extension AudioMessageView: ThemeSwitchProtocol {
    public func switchTheme(style: ThemeStyle) {
        if self.towards == .left {
            self.audioIcon.image = UIImage(chatNamed: "audio_message_icon_show_left")?.withTintColor(style == .dark ? UIColor.theme.neutralSpecialColor6:UIColor.theme.neutralSpecialColor5)
            self.audioIcon.animationImages = Appearance.chat.receiveAudioAnimationImages
        } else {
            self.audioIcon.image = UIImage(chatNamed: "audio_message_icon_show_right")?.withTintColor(style == .dark ? UIColor.theme.neutralSpecialColor6:UIColor.theme.neutralColor98)
            self.audioIcon.animationImages = Appearance.chat.sendAudioAnimationImages
        }
    }
}
  • 若只需支持亮色模式,仅需配置亮色模式相关的 hue 值即可。

Chat/消息条目的图片和国际化资源表

类别资源类型覆盖方式
video_message_play图片资源Bundle.main 中添加同名图片 video_message_play
thread_more图片资源Bundle.main 中添加同名图片 thread_more
reaction_trash图片资源Bundle.main 中添加同名图片 reaction_trash
uncheck图片资源Bundle.main 中添加同名图片 uncheck
check图片资源Bundle.main 中添加同名图片 check
text_message_edited图片资源Bundle.main 中添加同名图片 text_message_edited
text_message_translated图片资源Bundle.main 中添加同名图片 text_message_translated
select图片资源Bundle.main 中添加同名图片 select
unselect图片资源Bundle.main 中添加同名图片 unselect
No Messages国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 No Messages
Send国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Send
Sent国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Sent
Remove国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Remove
Confirm Remove国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Confirm Remove
Edited国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Edited
Translated国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Translated

Chat/Views 图片和国际化资源表

类别资源类型覆盖方式
audio_message_icon_show_left图片资源Bundle.main 中添加同名图片 audio_message_icon_show_left
audio_message_icon_show_right图片资源Bundle.main 中添加同名图片 audio_message_icon_show_right
reaction_all图片资源Bundle.main 中添加同名图片 reaction_all
file_message_icon图片资源Bundle.main 中添加同名图片 file_message_icon
mic_on图片资源Bundle.main 中添加同名图片 mic_on
trash图片资源Bundle.main 中添加同名图片 trash
send_audio图片资源Bundle.main 中添加同名图片 send_audio
edit_bar_status图片资源Bundle.main 中添加同名图片 edit_bar_status
audio图片资源Bundle.main 中添加同名图片 audio
attachment图片资源Bundle.main 中添加同名图片 attachment
attachmentSelected图片资源Bundle.main 中添加同名图片 attachmentSelected
emojiKeyboard图片资源Bundle.main 中添加同名图片 emojiKeyboard
textKeyboard图片资源Bundle.main 中添加同名图片 textKeyboard
message_select_bottom_forward图片资源Bundle.main 中添加同名图片 message_select_bottom_forward
more_messages图片资源Bundle.main 中添加同名图片 more_messages
pinned_messages图片资源Bundle.main 中添加同名图片 pinned_messages
Chat History国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Chat History
input_extension_menu_contact国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 input_extension_menu_contact
remaining国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 remaining
Record国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Record
Recording国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Recording
Play国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Play
Playing国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Playing
Editing国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Editing
new messages国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 new messages
Pin Messages国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Pin Messages
Sticky Message国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Sticky Message

MessageListController 图片和国际化资源表

类别资源类型覆盖方式
message_action_topic图片资源Bundle.main 中添加同名图片 message_action_topic
pinned_messages图片资源Bundle.main 中添加同名图片 pinned_messages
No pinned messages国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 No pinned messages
Typing...国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Typing...
Please select greater than one message.国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Please select greater than one message.
barrage_long_press_menu_delete国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 barrage_long_press_menu_delete
messages国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 messages
permissions disable国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 permissions disable
photo_disable国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 photo_disable
camera_disable国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 camera_disable
Share Contact国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 Share Contact
to国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 to
file_disable国际化资源Bundle.main 的 Localizable.strings 中添加 key 为 file_disable

可重载方法标记

MessageListController 及其组件类中的许多方法均标记为 open,可通过子类化深度定制业务逻辑。

上次编辑于: