总结所有步骤
1.自定义消息类型
2.自定义展示的消息Cell类
3.自定义消息内容的View(我这里使用xib,大家参考就好)
4.融云服务器建立连接成功后注册自定义的消息类型,会话页面类注册自定义消息的Cell
5.发送自定义消息
6.自定义消息的点击事件
7.会话页面类的一些处理(界面设置、扩展功能、长按消息撤回转发、自定义地图页面)
1.自定义消息类型(UsersModel是自定义的用户数据model)
let RCBusinessCardCellKey = "Kchat:businessCard" //个人名片
class BusinessCardMessage: RCMessageContent , NSCoding {
var id: Int = -1 //名片用户id
var title: String = "" //名片昵称
var detail: String = "" //名片用户账号(类似QQ)
var image: String = "" //名片头像
override init() {
super.init()
}
///初始化
class func messageWithContent(_ model: UsersModel) -> BusinessCardMessage {
let message = BusinessCardMessage()
message.id = model.id
message.title = model.nickname
message.detail = model.kNumber
message.image = model.headimgurl
return message
}
///消息是否存储,是否计入未读数
override class func persistentFlag() -> RCMessagePersistent {
return RCMessagePersistent.MessagePersistent_ISPERSISTED
}
// NSCoding
required init?(coder: NSCoder) {
super.init()
self.id = coder.decodeInteger(forKey: "id")
self.title = "\(coder.decodeObject(forKey: "title") ?? "")"
self.detail = "\(coder.decodeObject(forKey: "detail") ?? "")"
self.image = "\(coder.decodeObject(forKey: "image") ?? "")"
}
func encode(with coder: NSCoder) {
coder.encode(self.id, forKey: "id")
coder.encode(self.title, forKey: "title")
coder.encode(self.detail, forKey: "detail")
coder.encode(self.image, forKey: "image")
}
}
//MARK:*******************代理方法*******************
extension BusinessCardMessage {
///将消息内容编码成json
override func encode() -> Data! {
let dataDic: NSMutableDictionary = NSMutableDictionary()
dataDic.setValue(self.id, forKey: "id")
dataDic.setValue(self.title, forKey: "title")
dataDic.setValue(self.detail, forKey: "detail")
dataDic.setValue(self.image, forKey: "image")
return try! JSONSerialization.data(withJSONObject: dataDic, options: .prettyPrinted)
}
///将json解码生成消息内容
override func decode(with data: Data!) {
guard let dic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? NSDictionary else {
return
}
self.id = dic.intForKey("id")
self.title = dic.stringForKey("title")
self.detail = dic.stringForKey("detail")
self.image = dic.stringForKey("image")
}
//最后一条消息是自定义消息的时候,可以更改在会话列表显示的类型,为了区分消息类型
override func conversationDigest() -> String! {
return "[个人名片]"
}
//定义的消息类型名,需要在各个平台上保持一致,以保证消息互通,别以 RC 开头,以免和融云系统冲突
override class func getObjectName() -> String! {
return RCBusinessCardCellKey
}
}
2.自定义展示的消息Cell类
class BusinessCardMessageCell: RCMessageCell {
static let cellHeight: CGFloat = 84 //消息高度
var contentV: BusinessCardContentV? //消息内容view
//当应用自定义消息时,必须实现该方法来返回cell的Size
override class func size(for model: RCMessageModel!, withCollectionViewWidth collectionViewWidth: CGFloat, referenceExtraHeight extraHeight: CGFloat) -> CGSize {
return CGSize(width: collectionViewWidth, height: cellHeight + extraHeight)
}
//设置当前消息Cell的数据模型
override func setDataModel(_ model: RCMessageModel!) {
super.setDataModel(model)
setContentV(model)
}
//设置消息UI
func setContentV(_ model: RCMessageModel) {
if contentV == nil {
contentV = BusinessCardContentV().initContentV()
contentV?.model = model.content
//添加自定义消息点击事件
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(clickAction))
contentV?.addGestureRecognizer(tapGesture)
//添加自定义消息长按事件
let longGesture: UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longAction(_:)))
contentV?.addGestureRecognizer(longGesture)
messageContentView?.addSubview(contentV!)
}
var locationX: CGFloat = 0.0
//我方发送消息-右边布局
if model.messageDirection == .MessageDirection_SEND {
locationX = messageContentView.bounds.width - contentV!.bounds.width
contentV?.isSend = true
//他方发送消息-左边布局
} else {
contentV?.isSend = false
}
contentV?.setLocationX(x: locationX)
}
//MARK:-添加单击手势事件,会话页面的didTapMessageCell方法才会被执行
@objc func clickAction() {
delegate.didTapMessageCell?(model)
}
//MARK:-添加长按手势事件,会话页面的didLongTouchMessageCell方法才会被执行
@objc func longAction(_ longGesture: UILongPressGestureRecognizer) {
if longGesture.state != .began { return }
delegate.didLongTouchMessageCell?(model, in: self)
}
}
3.自定义消息内容的View(我这里使用xib,大家参考就好)
class BusinessCardContentV: UIView {
@IBOutlet weak var bgImageV: UIImageView!
@IBOutlet weak var contentViewLeft: NSLayoutConstraint!
@IBOutlet weak var imageV: UIImageView!
@IBOutlet weak var nameL: UILabel!
@IBOutlet weak var detailL: UILabel!
private var _model: RCMessageContent?
var model: RCMessageContent? {
set(newValue) {
_model = newValue
if newValue == nil { return }
guard let messageModel = newValue as? BusinessCardMessage else {
return
}
imageV.loadImage(imgUrl: messageModel.image, defaultImage: "morentu")
imageV.setContentFit()
nameL.text = messageModel.title
detailL.text = messageModel.detail
}
get { return _model }
}
var isSend: Bool = false {
didSet {
//我方发送消息-右边布局
if isSend {
bgImageV.image = UIImage(named: "liaotian27")
contentViewLeft.constant = 15
//他方发送消息-左边布局
} else {
bgImageV.image = UIImage(named: "liaotian26")
contentViewLeft.constant = 21
}
}
}
//初始化
func initContentV() -> BusinessCardContentV {
let contentV: BusinessCardContentV = Bundle.main.loadNibNamed("BusinessCardContentV", owner: nil, options: nil)?.first as! BusinessCardContentV
contentV.frame = CGRect(x: 0, y: 0, width: 235, height: 84)
return contentV
}
}
4.融云服务器建立连接成功后注册自定义的消息类型,会话页面类注册自定义消息的Cell
//融云服务器建立连接成功后注册自定义的消息类型
RCIM.shared().registerMessageType(BusinessCardMessage.self)
//继承RCConversationViewController的会话页面注册自定义消息的Cell
register(BusinessCardMessageCell.self, forMessageClass: BusinessCardMessage.self)
5.发送自定义消息
let message: BusinessCardMessage = BusinessCardMessage.messageWithContent(usersModel)
sendMessage(message, pushContent: "[个人名片]\(message.title)")
6.自定义消息的点击事件
//MARK:-点击消息
override func didTapMessageCell(_ model: RCMessageModel!) {
super.didTapMessageCell(model)
switch model.objectName {
case RCBusinessCardCellKey: //名片
//添加你需要的操作
default:
break
}
}
7.会话页面类的一些处理(界面设置、扩展功能、长按消息撤回转发、自定义地图页面)
//重写此方法,防止导航栏自定义按钮被置nil
override func notifyUpdateUnreadMessageCount() { }
//MARK:-设置CollectionView的属性
func setCollectionViewProperty() {
conversationMessageCollectionView.backgroundColor = UIColor.BackgroundColor()
conversationMessageCollectionView.showsVerticalScrollIndicator = false
//修改背景颜色
chatSessionInputBarControl.inputTextView.superview?.backgroundColor = RGBA(234, 237, 243, 1)
chatSessionInputBarControl.pluginBoardView.contentView.backgroundColor = RGBA(234, 237, 243, 1)
//修改输入框
chatSessionInputBarControl.inputTextView.layer.borderWidth = 0
chatSessionInputBarControl.inputTextView.layer.cornerRadius = 6
//去除发送地址功能
chatSessionInputBarControl.pluginBoardView.removeItem(at: 1003)
//添加扩展功能
chatSessionInputBarControl.pluginBoardView.insertItem(with: UIImage(named: "liaotian23"), title: "名片", tag: 202)
//自定义消息
register(BusinessCardMessageCell.self, forMessageClass: BusinessCardMessage.self)
}
//MARK:-扩展功能板的点击回调
override func pluginBoardView(_ pluginBoardView: RCPluginBoardView!, clickedItemWithTag tag: Int) {
super.pluginBoardView(pluginBoardView, clickedItemWithTag: tag)
weak var weakSelf = self
switch tag {
case 202: //名片
//添加你需要的操作
default: break
}
}
//MARK:-长按消息的回调
override func didLongTouchMessageCell(_ model: RCMessageModel!, in view: UIView!) {
super.didLongTouchMessageCell(model, in: view)
}
override func getLongTouchMessageCellMenuList(_ model: RCMessageModel!) -> [UIMenuItem]! {
var menuItems: [UIMenuItem] = super.getLongTouchMessageCellMenuList(model)
//设置某个类型不可撤回,为名片消息添加转发功能
switch model.objectName {
case RCXXXXXXXXCellKey:
for i in 0 ..< menuItems.count {
if menuItems[i].title != "撤回" { continue }
menuItems.remove(at: i)
break
}
case RCBusinessCardCellKey:
let transmitItem: UIMenuItem = UIMenuItem(title: "转发", action: #selector(transmitMessageAction))
menuItems.insert(transmitItem, at: 0)
transmitMessage = model
default:
break
}
return menuItems
}
//MARK:-转发消息
@objc func transmitMessageAction() {
//添加你需要的操作,如跳转到列表页面选择好友或者群来转发
}
//MARK:-点击位置消息跳转到自定义地图页面(自定义类继承RCLocationViewController,方便自定义UI)
override func presentLocationViewController(_ locationMessageContent: RCLocationMessage!) {
let vc = RCIMLocationVC()
vc.location = locationMessageContent.location
vc.locationName = locationMessageContent.locationName
pushViewControllerHideBar(vc, animated: true)
}
以上是我对接融云时候需要做的一些处理,大家对上述处理方式存在疑问或存在隐藏bug,请不吝留言,如果对你有用的话,点个赞哦。