Skip to content

Commit 59a1e78

Browse files
authored
Merge pull request #35 from zjc19891106/main
improve keyboard experience&custom multi cell
2 parents 1de0d07 + 3c2d43e commit 59a1e78

20 files changed

+410
-213
lines changed

Documentation/custom_cell.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ class RedPackageCell: CustomMessageCell {
3131

3232
```
3333

34-
35-
[图示](./red_package_message.jpg)
36-
3734
## 2.根据需求继承`EaseChatUIKit`中的Cell的渲染模型`MessageEntity`,并给定气泡大小,其中`redPackageIdentifier`为红包的自定义消息的event事件
3835

3936
```Swift
@@ -71,9 +68,6 @@ final class MineMessageEntity: MessageEntity {
7168

7269
## 3.添加发送附件消息的类型
7370

74-
75-
[图示](./send_red_package.jpg)
76-
7771
示例,增加发送红包消息
7872

7973
```Swift
@@ -151,13 +145,11 @@ extension MessageListViewModel {
151145
ComponentsRegister.shared.MessageRenderEntity = MineMessageEntity.self
152146
ComponentsRegister.shared.Conversation = MineConversationInfo.self
153147
ComponentsRegister.shared.MessageViewController = CustomMessageListController.self
154-
ComponentsRegister.shared.registerCustomizeCellClass(cellType: RedPackageCell.self)
148+
//redPackageIdentifier 为Cell的唯一标识,也是环信自定义消息的时间类型
149+
ComponentsRegister.shared.registerCustomCellClasses(cellType: RedPackageCell.self,identifier: redPackageIdentifier)
155150
```
156151

157152
- 这里`ComponentsRegister.shared.Conversation = MineConversationInfo.self`是为了修改自定义消息在会话列表中,会话收到新消息时显示的内容这里暂定为显示 "[红包]",示例代码如下,主要更改在非文本消息类型的else中根据自定义消息的event显示对应的内容
158-
159-
[图示](./red_package_placeholder.jpg)
160-
161153
```Swift
162154
import UIKit
163155
import EaseChatUIKit

Example/EaseChatUIKit.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
059853352CF08F9900A7825D /* MineMessageEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059853342CF08F9900A7825D /* MineMessageEntity.swift */; };
1717
059853372CF0971400A7825D /* MineConversationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059853362CF0971400A7825D /* MineConversationInfo.swift */; };
1818
0598E6992B366F5D0079BF47 /* HueSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0598E6982B366F5D0079BF47 /* HueSettingViewController.swift */; };
19+
05AA4E392D13C47100E81E90 /* GiftCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA4E382D13C47100E81E90 /* GiftCell.swift */; };
20+
05AA4E3B2D13C7A300E81E90 /* MusicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA4E3A2D13C7A300E81E90 /* MusicCell.swift */; };
1921
05BF34412B2C2F29004639CE /* OptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05BF34402B2C2F29004639CE /* OptionsViewController.swift */; };
2022
0FD976A5382D36AF6B70D22C /* Pods_EaseChatUIKit_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93876C90F7ED383C7B3B2838 /* Pods_EaseChatUIKit_Example.framework */; };
2123
607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
@@ -38,6 +40,8 @@
3840
059853362CF0971400A7825D /* MineConversationInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineConversationInfo.swift; sourceTree = "<group>"; };
3941
0598E6982B366F5D0079BF47 /* HueSettingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HueSettingViewController.swift; sourceTree = "<group>"; };
4042
059AD7A42B29A3BB0043D299 /* VoiceConvert.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VoiceConvert.xcframework; path = ../Sources/EaseChatUIKit/Classes/UI/Core/UIKit/FrameWorks/VoiceConvert.xcframework; sourceTree = "<group>"; };
43+
05AA4E382D13C47100E81E90 /* GiftCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCell.swift; sourceTree = "<group>"; };
44+
05AA4E3A2D13C7A300E81E90 /* MusicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicCell.swift; sourceTree = "<group>"; };
4145
05BF34402B2C2F29004639CE /* OptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionsViewController.swift; sourceTree = "<group>"; };
4246
5BD01E2EA5ABF01A40AF9C88 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
4347
607FACD01AFB9204008FA782 /* EaseChatUIKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EaseChatUIKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -102,6 +106,8 @@
102106
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
103107
607FACD31AFB9204008FA782 /* Supporting Files */,
104108
059853302CF08A9B00A7825D /* RedPackageCell.swift */,
109+
05AA4E382D13C47100E81E90 /* GiftCell.swift */,
110+
05AA4E3A2D13C7A300E81E90 /* MusicCell.swift */,
105111
059853322CF08ADE00A7825D /* CustomMessageListController.swift */,
106112
059853342CF08F9900A7825D /* MineMessageEntity.swift */,
107113
059853362CF0971400A7825D /* MineConversationInfo.swift */,
@@ -294,12 +300,14 @@
294300
buildActionMask = 2147483647;
295301
files = (
296302
0598E6992B366F5D0079BF47 /* HueSettingViewController.swift in Sources */,
303+
05AA4E3B2D13C7A300E81E90 /* MusicCell.swift in Sources */,
297304
0500149B2B2AA725000DA9CE /* LoginViewController.swift in Sources */,
298305
607FACD81AFB9204008FA782 /* SettingViewController.swift in Sources */,
299306
059853352CF08F9900A7825D /* MineMessageEntity.swift in Sources */,
300307
607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */,
301308
059853332CF08ADE00A7825D /* CustomMessageListController.swift in Sources */,
302309
059853372CF0971400A7825D /* MineConversationInfo.swift in Sources */,
310+
05AA4E392D13C47100E81E90 /* GiftCell.swift in Sources */,
303311
0500149F2B2AAA7E000DA9CE /* MainViewController.swift in Sources */,
304312
0565FBB12B4D127700F75C4A /* CustomConversationViewController.swift in Sources */,
305313
059853312CF08A9B00A7825D /* RedPackageCell.swift in Sources */,

Example/EaseChatUIKit/AppDelegate.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
1818

1919
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
2020
// Override point for customization after application launch.
21-
let option = ChatOptions(appkey: <#AppKey#>)
21+
let option = ChatOptions(appkey: <#环信AppKey#>)
2222
option.enableConsoleLog = true
2323
_ = ChatUIKitClient.shared.setup(option: option)
24-
let redPackage = ActionSheetItem(title: "红包".chat.localize, type: .normal,tag: "Red",image: UIImage(named: "photo", in: .chatBundle, with: nil))
24+
let redPackage = ActionSheetItem(title: "Red".chat.localize, type: .normal,tag: "Red",image: UIImage(named: "photo", in: .chatBundle, with: nil))
25+
let gift = ActionSheetItem(title: "Gift".chat.localize, type: .normal,tag: "Gift",image: UIImage(named: "photo", in: .chatBundle, with: nil))
26+
let music = ActionSheetItem(title: "Music".chat.localize, type: .normal,tag: "Music",image: UIImage(named: "photo", in: .chatBundle, with: nil))
27+
ComponentsRegister.shared.registerCustomCellClasses(cellType: RedPackageCell.self, identifier: redPackageIdentifier)
28+
ComponentsRegister.shared.registerCustomCellClasses(cellType: GiftCell.self, identifier: giftIdentifier)
29+
ComponentsRegister.shared.registerCustomCellClasses(cellType: MusicCell.self, identifier: musicIdentifier)
30+
2531
Appearance.chat.inputExtendActions.append(redPackage)
32+
Appearance.chat.inputExtendActions.append(gift)
33+
Appearance.chat.inputExtendActions.append(music)
2634
ComponentsRegister.shared.MessageRenderEntity = MineMessageEntity.self
2735
ComponentsRegister.shared.Conversation = MineConversationInfo.self
2836
ComponentsRegister.shared.MessageViewController = CustomMessageListController.self
29-
ComponentsRegister.shared.registerCustomizeCellClass(cellType: RedPackageCell.self)
3037
return true
3138
}
3239

Example/EaseChatUIKit/CustomConversationViewController.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class CustomConversationViewController: ConversationListController {
1919
override func createList() -> ConversationList {
2020
ConversationList()
2121
}
22+
23+
2224

2325
override func viewDidLoad() {
2426
super.viewDidLoad()

Example/EaseChatUIKit/CustomMessageListController.swift

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,16 @@ import UIKit
1010
import EaseChatUIKit
1111

1212
class CustomMessageListController: MessageListController {
13-
14-
override func processFollowInputAttachmentAction() {
15-
if Appearance.chat.messageAttachmentMenuStyle == .followInput {
16-
if let fileItem = Appearance.chat.inputExtendActions.first(where: { $0.tag == "File" }) {
17-
fileItem.action = { [weak self] item,object in
18-
self?.handleAttachmentAction(item: item)
19-
}
20-
}
21-
if let photoItem = Appearance.chat.inputExtendActions.first(where: { $0.tag == "Photo" }) {
22-
photoItem.action = { [weak self] item,object in
23-
self?.handleAttachmentAction(item: item)
24-
}
25-
}
26-
if let cameraItem = Appearance.chat.inputExtendActions.first(where: { $0.tag == "Camera" }) {
27-
cameraItem.action = { [weak self] item,object in
28-
self?.handleAttachmentAction(item: item)
29-
}
30-
}
31-
if let contactItem = Appearance.chat.inputExtendActions.first(where: { $0.tag == "Contact" }) {
32-
contactItem.action = { [weak self] item,object in
33-
self?.handleAttachmentAction(item: item)
34-
}
35-
}
36-
if let redPackageItem = Appearance.chat.inputExtendActions.first(where: { $0.tag == "Red" }) {
37-
redPackageItem.action = { [weak self] item,object in
38-
self?.handleAttachmentAction(item: item)
39-
}
40-
}
41-
42-
}
43-
}
44-
13+
4514
override func handleAttachmentAction(item: any ActionSheetItemProtocol) {
4615
switch item.tag {
4716
case "File": self.selectFile()
4817
case "Photo": self.selectPhoto()
4918
case "Camera": self.openCamera()
5019
case "Contact": self.selectContact()
5120
case "Red": self.redPackageMessage()
21+
case "Gift": self.giftMessage()
22+
case "Music": self.musicMessage()
5223
default:
5324
break
5425
}
@@ -58,19 +29,31 @@ class CustomMessageListController: MessageListController {
5829
self.viewModel.sendRedPackageMessage()
5930
}
6031

32+
private func giftMessage() {
33+
self.viewModel.sendGiftMessage()
34+
}
35+
36+
private func musicMessage() {
37+
self.viewModel.sendMusicMessage()
38+
}
39+
6140
}
6241

6342
let redPackageIdentifier = "redPackage"
6443

44+
let giftIdentifier = "gift"
45+
46+
let musicIdentifier = "music"
47+
6548
extension MessageListViewModel {
6649
func sendRedPackageMessage() {
6750
var ext = Dictionary<String,Any>()
68-
ext["something"] = "发红包"
51+
ext["something"] = "Send Red Package"
6952
let json = ChatUIKitContext.shared?.currentUser?.toJsonObject() ?? [:]
7053
ext.merge(json) { _, new in
7154
new
7255
}
73-
let chatMessage = ChatMessage(conversationID: self.to, body: ChatCustomMessageBody(event: redPackageIdentifier, customExt: ["money": "20", "name": "张三","message": "恭喜发财大吉大利"]), ext: ext)
56+
let chatMessage = ChatMessage(conversationID: self.to, body: ChatCustomMessageBody(event: redPackageIdentifier, customExt: ["money": "20", "name": "zhangsan","message": "Hello World"]), ext: ext)
7457
self.driver?.showMessage(message: chatMessage)
7558
self.chatService?.send(message: chatMessage) { [weak self] error, message in
7659
if error == nil {
@@ -86,6 +69,51 @@ extension MessageListViewModel {
8669
}
8770
}
8871

72+
func sendGiftMessage() {
73+
var ext = Dictionary<String,Any>()
74+
ext["something"] = "Send Gift"
75+
let json = ChatUIKitContext.shared?.currentUser?.toJsonObject() ?? [:]
76+
ext.merge(json) { _, new in
77+
new
78+
}
79+
let chatMessage = ChatMessage(conversationID: self.to, body: ChatCustomMessageBody(event: giftIdentifier, customExt: ["gift": "gift"]), ext: ext)
80+
self.driver?.showMessage(message: chatMessage)
81+
self.chatService?.send(message: chatMessage) { [weak self] error, message in
82+
if error == nil {
83+
if let message = message {
84+
self?.driver?.updateMessageStatus(message: message, status: .succeed)
85+
}
86+
} else {
87+
consoleLogInfo("send text message failure:\(error?.errorDescription ?? "")", type: .error)
88+
if let message = message {
89+
self?.driver?.updateMessageStatus(message: message, status: .failure)
90+
}
91+
}
92+
}
93+
}
94+
95+
func sendMusicMessage() {
96+
var ext = Dictionary<String,Any>()
97+
ext["something"] = "Send music"
98+
let json = ChatUIKitContext.shared?.currentUser?.toJsonObject() ?? [:]
99+
ext.merge(json) { _, new in
100+
new
101+
}
102+
let chatMessage = ChatMessage(conversationID: self.to, body: ChatCustomMessageBody(event: musicIdentifier, customExt: ["music": "music"]), ext: ext)
103+
self.driver?.showMessage(message: chatMessage)
104+
self.chatService?.send(message: chatMessage) { [weak self] error, message in
105+
if error == nil {
106+
if let message = message {
107+
self?.driver?.updateMessageStatus(message: message, status: .succeed)
108+
}
109+
} else {
110+
consoleLogInfo("send text message failure:\(error?.errorDescription ?? "")", type: .error)
111+
if let message = message {
112+
self?.driver?.updateMessageStatus(message: message, status: .failure)
113+
}
114+
}
115+
}
116+
}
89117

90118
}
91119

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// GiftCell.swift
3+
// EaseChatUIKit_Example
4+
//
5+
// Created by 朱继超 on 12/19/24.
6+
// Copyright © 2024 CocoaPods. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import EaseChatUIKit
11+
12+
class GiftCell: CustomMessageCell {
13+
14+
lazy var gift: UILabel = {
15+
UILabel().textAlignment(.center).textColor(.white).font(.systemFont(ofSize: 16)).backgroundColor(.clear)
16+
}()
17+
18+
required init(towards: BubbleTowards, reuseIdentifier: String) {
19+
super.init(towards: towards, reuseIdentifier: reuseIdentifier)
20+
self.content.addSubview(self.gift)
21+
}
22+
23+
@MainActor required init?(coder: NSCoder) {
24+
fatalError("init(coder:) has not been implemented")
25+
}
26+
27+
override func createContent() -> UIView {
28+
UIView(frame: self.contentView.bounds).backgroundColor(.clear).tag(bubbleTag)
29+
}
30+
31+
override func layoutSubviews() {
32+
super.layoutSubviews()
33+
self.gift.frame = self.content.bounds
34+
}
35+
36+
override func refresh(entity: MessageEntity) {
37+
super.refresh(entity: entity)
38+
if let body = entity.message.body as? ChatCustomMessageBody,body.event == giftIdentifier {
39+
self.gift.text = body.event
40+
}
41+
}
42+
43+
override func updateAxis(entity: MessageEntity) {
44+
super.updateAxis(entity: entity)
45+
46+
}
47+
48+
}

Example/EaseChatUIKit/LoginViewController.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ extension LoginViewController {
4747
ChatUIKitClient.shared.logout(unbindNotificationDeviceToken: false) { [weak self] _ in
4848
guard let `self` = self else { return }
4949
guard let userName = self.userNameField.text,let passWord = self.passWordField.text,!userName.isEmpty,!passWord.isEmpty else { return }
50-
self.userName = userName.lowercased()
50+
self.userName = userName.lowercased()
5151
self.passWord = passWord
5252
let profile = ChatUserProfile()
5353
profile.id = userName.lowercased()
5454
profile.nickname = "Tester 001"
55-
profile.avatarURL = "https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/sample_avatar/sample_avatar_1.png"
56-
ChatUIKitClient.shared.login(user: profile, token: "YWMtrBLRHrjtEe-IODH5J7D-t1zzvlQ7sUrSpVuQGlyIzFQLSg3AGHsR7bfQlcHY0wi4AwMAAAGTvYg04AAAjKBtZLdDVioXxzdjKdcRBpgxcIah52G6mqXF9GvrZUhB8g") { error in
55+
profile.avatarURL = "https://xxx"
56+
ChatUIKitClient.shared.login(user: profile, token: passWord) { error in
5757
if error == nil {
5858
UIApplication.shared.chat.keyWindow?.rootViewController = MainViewController()
5959
} else {

Example/EaseChatUIKit/MainViewController.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ extension MainViewController: ThemeSwitchProtocol {
145145
//MARK: - EaseProfileProvider for conversations&contacts usage.
146146
//For example using conversations controller,as follows.
147147
extension MainViewController: ChatUserProfileProvider,ChatGroupProfileProvider {
148-
//MARK: - EaseProfileProvider
148+
//MARK: - ChatUserProfileProvider
149149
func fetchProfiles(profileIds: [String]) async -> [any EaseChatUIKit.ChatUserProfileProtocol] {
150150
return await withTaskGroup(of: [EaseChatUIKit.ChatUserProfileProtocol].self, returning: [EaseChatUIKit.ChatUserProfileProtocol].self) { group in
151151
var resultProfiles: [EaseChatUIKit.ChatUserProfileProtocol] = []
@@ -164,7 +164,7 @@ extension MainViewController: ChatUserProfileProvider,ChatGroupProfileProvider {
164164
return resultProfiles
165165
}
166166
}
167-
//MARK: - EaseGroupProfileProvider
167+
//MARK: - ChatGroupProfileProvider
168168
func fetchGroupProfiles(profileIds: [String]) async -> [any EaseChatUIKit.ChatUserProfileProtocol] {
169169

170170
return await withTaskGroup(of: [EaseChatUIKit.ChatUserProfileProtocol].self, returning: [EaseChatUIKit.ChatUserProfileProtocol].self) { group in
@@ -238,6 +238,8 @@ extension MainViewController: ChatUserProfileProvider,ChatGroupProfileProvider {
238238
return resultProfiles
239239
}
240240
}
241+
242+
241243
//MARK: - ConversationEmergencyListener
242244
extension MainViewController: ConversationEmergencyListener {
243245
func onResult(error: EaseChatUIKit.ChatError?, type: EaseChatUIKit.ConversationEmergencyType) {

Example/EaseChatUIKit/MineConversationInfo.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,13 @@ final class MineConversationInfo: ConversationInfo {
6666
} else {
6767
var content = message.showContent
6868
if let body = message.body as? ChatCustomMessageBody,body.event == redPackageIdentifier {
69-
content = "[红包]"
69+
content = "[Red Package]"
70+
}
71+
if let body = message.body as? ChatCustomMessageBody,body.event == giftIdentifier {
72+
content = "[Gift]"
73+
}
74+
if let body = message.body as? ChatCustomMessageBody,body.event == musicIdentifier {
75+
content = "[Music]"
7076
}
7177
let showText = NSMutableAttributedString {
7278
AttributedText((message.chatType == .chat ? content:(nickName+":"+content))).foregroundColor(Theme.style == .dark ? UIColor.theme.neutralColor6:UIColor.theme.neutralColor5).font(UIFont.theme.bodyMedium)

Example/EaseChatUIKit/MineMessageEntity.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ final class MineMessageEntity: MessageEntity {
2323
return CGSize(width: ScreenWidth-32, height: size.height+50)
2424
case redPackageIdentifier:
2525
return CGSize(width: limitBubbleWidth, height: limitBubbleWidth*(5/3.0))
26+
case giftIdentifier:
27+
return CGSize(width: limitBubbleWidth, height: 70)
28+
case musicIdentifier:
29+
return CGSize(width: limitBubbleWidth, height: 80)
2630
default:
2731
return .zero
2832
}

0 commit comments

Comments
 (0)