之前有做過和即時通訊相關(guān)的項目,不過貌似已經(jīng)下架了,源碼也找不到了。因為下個項目可能會涉及即時通訊,所以最近幾天把環(huán)信即使通訊的相關(guān)東西又稍微在整理了一些,寫了個小的demo。demo中有登錄、注冊、發(fā)送文字、圖片、聲音消息、群聊、單聊、獲取會話列表、未讀消息通知、自定義聊天界面、自定義鍵盤、增加刪除好好和組等功能,總的來說功能還算齊全,寫的也比較隨意,整個結(jié)構(gòu)沒給整理好,因為最開始想的就是隨便熟悉一下,誰知后來寫了很多功能。這個demo中的聊天界面以及自定義鍵盤都是自己寫的,目前還存在一些不完善的地方,以后有時間了回給補充一下,如發(fā)送消息時聊天界面進度信息。簡單看一下效果圖。
其中的聊天面板和鍵盤都是自己寫的,鍵盤只是寫了個大概,還沒有增加自定義表情,后期會繼續(xù)完善,可能會增加圖文混排功能,自定義表情功能。例外就是因為項目結(jié)構(gòu)沒有搭建的很好,所以最開始在處理收到好友加自己為好友這樣的功能存在一些問題。這里主要是告訴一些新手使用環(huán)信實現(xiàn)這種即時通訊app的一些注意事項,以及搭建聊天界面和自定義鍵盤比較好的思路。實際上搭建一個功能比較完善的聊天界面還是很麻煩的,一般情況下很多人可能就會直接選擇EaseUI。當然,如果想挑戰(zhàn)一下,不防稍微試試。
1.關(guān)閉控制臺登錄信息的打印。
EMError *error = [[EaseMob sharedInstance]registerSDKWithAppKey:@"zhengyawei#zhuanxintestzyw" apnsCertName:@"HuanXinp12" otherConfig:@{kSDKConfigEnableConsoleLogger:@NO}];
2.調(diào)用環(huán)信的程序加載完畢的方法,才能添加代理。之后才能調(diào)用代理方法,否則代理方法不生效。
[[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
3.發(fā)送文本消息是要注意,去掉\n字符,否則可能聊天界面會無緣無故多出一行。記得之前在這個上面吃過虧,當時怎么也找不出原因。
//**1.接收信息者
/*==============================*/
NSString *receiver = self.isGroup? self.group.groupId: self.budddy.username;
//**2.內(nèi)容對象
//這里去掉\n
EMChatText *chatText = [[EMChatText alloc]initWithText:[textView.text substringToIndex:textView.text.length - 1]];
//**3.創(chuàng)建文本消息體
EMTextMessageBody *textBody = [[EMTextMessageBody alloc]initWithChatObject:chatText];
//**4.創(chuàng)建EMMessage對象
EMMessage *msg = [[EMMessage alloc]initWithReceiver:receiver bodies:@[textBody]];
/*==============================*/
msg.messageType = self.isGroup? eMessageTypeGroupChat:eMessageTypeChat;
//**5.異步發(fā)送消息
[[EaseMob sharedInstance].chatManager asyncSendMessage:msg progress:self prepare:^(EMMessage *message, EMError *error) {
NSLog(@"準備發(fā)送文本消息");
} onQueue:nil completion:^(EMMessage *message, EMError *error) {
NSLog(@"文本消息發(fā)送成功");
[self.messageData addObject:message];
[self scrollBottom];
//發(fā)送成功后清除數(shù)據(jù)
textView.text = @"";
} onQueue:nil];
};
4.添加過代理后,必須設(shè)置移除代理,所有界面都是如此
-(void)dealloc{
[[EaseMob sharedInstance].chatManager removeDelegate:self];
}
- 下面這個方法主要是聊天管理器, 獲取該對象后, 可以做登錄、聊天、加好友等操作。注意,在獲取會話列表之前要調(diào)用這句代碼,否則可能出現(xiàn)會話列表部分信息顯示不完全。
[[EaseMob sharedInstance].chatManager loadDataFromDatabase];
6.- (void)didReceiveBuddyRequest:(NSString *)username message:(NSString *)message;類似這種收到好友請求和被被人拉入群的通知,這樣的代理方法要放到tabBarController中記性管理。如果隨便放置,可能收不到這樣的通知,而且控制臺會打印錯誤信息。
7.關(guān)于聊天界面的布局。
在聊天界面布局的時候最好是在控制器的view上,再添加一個sccrollView,然后再將聊天界面的tableView以及自定義鍵盤的工具條放置到這個scrolleView上。這樣更能方便在鍵盤彈出時,管理tableView上消息位置的滑動。思路是這樣的:在鍵盤彈出的時候,讓整個scrollView都忘上升。這樣工具條和tableView都會同步上升。另外還要充分利用tableView的contentInset屬性,自我感覺這個屬性如果用好了,在實際項目中可以處理很多問題。在聊天界面中,這個屬性的主要解決的問題是:防止聊天記錄中內(nèi)容過少,鍵盤彈出時聊天記錄看不見。只需簡單一行代碼就能解決這個問題。代碼如下:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrameNotification:) name:UIKeyboardWillChangeFrameNotification object:nil];
- (void)keyboardWillChangeFrameNotification:(NSNotification *)noti
{
CGRect keyboardF = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
if (keyboardF.origin.y < kWeChatScreenHeight) {
self.contentView.top = - keyboardF.size.height;
//設(shè)置tableView的內(nèi)邊距,防止聊天記錄中內(nèi)容過少,鍵盤彈出時聊天記錄看不見
self.chatTableView.contentInset = UIEdgeInsetsMake(keyboardF.size.height, 0, 0, 0);
//鍵盤彈出時,tableView也要滾到最底部
//這里要做這樣的判斷,防止沒有聊天記錄的時候,出現(xiàn)數(shù)組越界
if (self.messageData.count != 0 ) {
[self.chatTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messageData.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}else{
self.contentView.top = 0;
self.chatTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
}
8.聊天界面的文字消息、圖片消息以及聲音消息,建議都使用UIButton這個空間進行處理。因為這些聲音消息和圖片消息,都涉及到點擊事件。可能后期如果想擴充地理位置,視頻消息也會涉及點擊事件,如果都是添加點擊手勢,感覺會過于麻煩。因為UIBUtton本身就帶有image和titleLabel屬性,所以圖片和文字消息都可以在上面進行展示。調(diào)節(jié)UIButton上的圖片和文字位置主要可以通過下面這兩行代碼:
//具體位置根據(jù)實際需求進行調(diào)節(jié)
self.chatBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
self.chatBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
9.關(guān)于自定義鍵盤如果更方便的在鍵盤和自定義視圖之間進行切換。這里主要提供兩種思路。
第一種方法是,將聊天面板添加到[UIApplication sharedApplication].keyWindow上,在切換鍵盤的時候控制聊天面板的y值。不過這種方法使用起來設(shè)計到的邏輯判斷會比較多,不是很方便,更推薦使用第二種方法。
第二種發(fā)放實現(xiàn)思路,充分利用UITextView或UITextField的inputView屬性,首先要知道當_textView.inputView = nil的時候,則顯示輸入視圖inputView就是系統(tǒng)的鍵盤;如果是自己_textView.inputView = customeView,這是顯示的就是自己自定義的視圖。通過在nil和customeView這兩個值之間的切換,就可以實現(xiàn)在鍵盤和自定義視圖之間的切換,根本沒有涉及太多的邏輯。注意:如果想封裝一個屬于自己的自定義鍵盤,這個inputView屬性起到的作用很大。
#pragma mark - 表情和鍵盤面板切換
- (void)keyBoardButtonClick:(UIButton *)btn{
if (btn.isSelected == NO) {//切換到表情
_textView.inputView = self.faceBoard;
btn.selected = YES;
}else{//切換到系統(tǒng)鍵盤
UIView *view = [[UIView alloc]init];
view.backgroundColor = [UIColor cyanColor];
view.frame = CGRectMake(0, 0, self.view.frame.size.width, 100);
_textView.inputView = nil;
btn.selected = NO;
}
if (_textView.isFirstResponder == YES) {
[_textView resignFirstResponder];
[_textView becomeFirstResponder];
}else{
[_textView becomeFirstResponder];
}
}
Demo下載地址:https://pan.baidu.com/s/1nuF1puL