iOS開發(fā)之環(huán)信(三)---界面搭建

聊天控制器(ChatViewController)界面搭建

14.聊天界面-工具條排版

1)搭建界面

添加聊天控制器:到mainstoryboard中找到addressbook的tableview控制器,將cell拖線給一個uiviewcontroller選擇show诊胞,在該控制器導(dǎo)航欄中間拖一個navigationitem昨稼,修改名為“聊天界面”咽袜,拖一個uiew尺寸與底部tabar一樣大小,并隱藏底部的tabar(1.點擊控制器bottombar選擇為none.2.點擊控制器勾選Hide Bottom Bar

on Push)歇由。(注意輸入框為textview),中間部分拖一個tableview,自動布局切省,設(shè)置代理,注意tableview中有個屬性帕胆,拖動時隱藏鍵盤(scrollview-keyboard-選擇dissmiss on drag)

自定義該聊天控制器:chatviewcontroller朝捆,將storyboard中控制器class改為該控制器的類名。

2)實現(xiàn)鍵盤退出懒豹、彈出芙盘,工具欄緊鏈接功能:控制器代碼如下:

//1.將工具條底部的約束拖線為該控制器的屬性。

@property(weak,nonatomic)IBOutletNSLayoutConstraint*chatInputBottomConstant;

//2.viewdidload中監(jiān)聽鍵盤彈出/回方法

//1).監(jiān)聽鍵盤彈出脸秽,把inputToolbar(輸入工具條)往上移

[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(kbWillShow:)name:UIKeyboardWillShowNotificationobject:nil];

//2).監(jiān)聽鍵盤退出儒老,inputToolbar恢復(fù)原位

[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(kbWillHide:)name:UIKeyboardWillHideNotificationobject:nil];

//3.實現(xiàn)監(jiān)聽方法

#pragma mark鍵盤顯示時會觸發(fā)的方法

-(void)kbWillShow:(NSNotification*)noti{

//1.獲取鍵盤高度

//1.1獲取鍵盤結(jié)束時候的位置

CGRectkbEndFrm = [noti.userInfo[UIKeyboardFrameEndUserInfoKey]CGRectValue];

CGFloatkbHeight = kbEndFrm.size.height;

//2.更改inputToolbar底部約束

self.chatInputBottomConstant.constant= kbHeight;

//添加動畫

[UIViewanimateWithDuration:0.25animations:^{

[self.viewlayoutIfNeeded];

}];

}

#pragma mark鍵盤退出時會觸發(fā)的方法

-(void)kbWillHide:(NSNotification*)noti{

//inputToolbar恢復(fù)原位

self.chatInputBottomConstant.constant=0;

}

//4.注銷監(jiān)聽者

-(void)dealloc{

[[NSNotificationCenterdefaultCenter]removeObserver:self];

}

15.聊天界面-接收方cell的排版

經(jīng)過分析,cell有三種類型:接受方cell记餐、發(fā)送方cell驮樊、時間cell。

在剛才拖入的tableview上拖一個cell重命名為receivecell片酝,再改cell中拖入控件并自動布局巩剖,給cell設(shè)置重用標(biāo)識為receivecell

注意:布局消息框:思想:底部為圖片,上面為label钠怯,先布局label佳魔,然后布局imageview,讓他與label大小一樣晦炊,然后修改約束使iamgeview周圍都比label周圍大一點鞠鲜。

A.布局label:Label布局為距離頂部15宁脊,左邊20。換行:點擊label-lines = 0贤姆、(設(shè)置label最大寬度)點擊尺子- preferred width = 242勾選榆苞,回車

B.布局uiiamgeview:cell中拖一個UIimageview,從左邊的列表中找到該imageview霞捡,拖到label的后面坐漏,同時選中l(wèi)abel、iamgeview碧信、設(shè)置四邊距都對齊約束赊琳,然后update,給iamgeview添加背景圖片砰碴,圖片拉伸:點擊imageview-streching-x:0.5/y:0.7,其余都為0躏筏。找到iamgeview的所有約束,給四周約束分別調(diào)10個間距大小呈枉。

自定義cell趁尼,view-ChatCell,將剛才storyboard中的cell的class改為該類猖辫。將上面那個label拖線到.h文件(必須)為屬性

控制器中數(shù)據(jù)源和代理的方法實現(xiàn)如下(測試而已):

-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{

return20;

}

-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{

return200;

}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{

staticNSString*ID =@"ReceiverCell";

ChatCell*cell = [tableViewdequeueReusableCellWithIdentifier:ID];

//顯示內(nèi)容

cell.chatLabel.text=@"asrqwerqwerqwerqwerqwfaskdjlfalsk;dfjalksjdflaksjdfa;sjdfklajsdkfljasfkal;sdkfjalksjdfa;jsdflkajsdf;lajskdf;las";

returncell;

}

16.聊天界面-發(fā)送方cell的排版

1).tableview中再拖一個cell酥泞,同理搭建sendcell(注意:將label脫線到cell中的同一個屬性中)

2).設(shè)置cell的高度:在自定義cell中實現(xiàn)計算cell的高度)

//專門用來計算高度的一個cell(注意理解)

#import

staticNSString*ReceiverCell =@"ReceiverCell";

staticNSString*SenderCell =@"SenderCell";

@interfaceChatCell :UITableViewCell

@property(weak,nonatomic)IBOutletUILabel*chatLabel;

-(CGFloat)cellHeghit;

@end

#import"ChatCell.h"

@implementationChatCell

/**返回cell的高度*/

-(CGFloat)cellHeghit{

//1.重新布局子控件

[selflayoutIfNeeded];

return5+10+self.chatLabel.bounds.size.height+10+5;

}

@end

3).控制器中實現(xiàn)的方法

a.添加屬性

@property(weak,nonatomic)IBOutletUITableView*tableView;

/**數(shù)據(jù)源*/

@property(nonatomic,strong)NSMutableArray*dataSources;

/**計算高度的cell工具對象(就是一個工具,給我文字長度我就能計算高度)*/

@property(nonatomic,strong)ChatCell*chatCellTool;

b.viewdidload初始化數(shù)據(jù)源

-(NSMutableArray*)dataSources{

if(!_dataSources) {

_dataSources= [NSMutableArrayarray];

}

return_dataSources;

}

//初始化數(shù)(好幾個長的)據(jù)

[self.dataSourcesaddObject:@"xcsafasdffsadfa"];

[self.dataSourcesaddObject:@"xcsafasdfsadxcssafasdfsadfafa"];

[self.dataSourcesaddObject:@"xcsafasdfxcsaadfasadfa"];

//給計算高度的cell工具對象賦值(就是初始化工具對象,也可以為sendcell)

self.chatCellTool= [self.tableViewdequeueReusableCellWithIdentifier:ReceiverCell];

c.重新實現(xiàn)數(shù)據(jù)源方法

-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{

returnself.dataSources.count;

}

-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{

//設(shè)置label的數(shù)據(jù)

#warning計算高度與前,一定要給chatLabel.text賦值

self.chatCellTool.chatLabel.text=self.dataSources[indexPath.row];

return[self.chatCellToolcellHeghit];

}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{

ChatCell*cell =nil;

if(indexPath.row%2==0) {//發(fā)送方的cell

cell = [tableViewdequeueReusableCellWithIdentifier:SenderCell];

}else{//接收發(fā)方的cell

cell = [tableViewdequeueReusableCellWithIdentifier:ReceiverCell];

}

//顯示內(nèi)容

cell.chatLabel.text=self.dataSources[indexPath.row];

returncell;

}

消息管理

消息:IM交互實體啃憎,在SDK中對應(yīng)的類型是EMMessage婶博。EMMessage由EMMessageBody組成.

總結(jié):與消息相關(guān)的網(wǎng)絡(luò)請求都用到[[EMClientsharedClient].chatManager聊天管理者

獲取一個人的會話列表用EMConversation類

17.聊天界面-發(fā)送聊天消息

步驟:

在mainstoryboard中找到聊天界面的輸入框textView,點擊-return-send

監(jiān)聽該send事件:拖線該textfield的代理到聊天控制器(ChatViewController)荧飞。控制器遵守代理(UITextViewDelegate)名党,并實現(xiàn)代理方法

導(dǎo)入頭文件:#import "EMSDK.h"(用多了可以添加到pch文件中)

1).給該控制器添加一個外部屬性

//要發(fā)送人的名字

@property(nonatomic,copy)NSString*buddy;

2).在通訊錄控制器(AddressBookViewController)中傳值叹阔,代碼如下:

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender{

//往聊天控制器傳遞一個buddy的值

iddestVC = segue.destinationViewController;

if([destVCisKindOfClass:[ChatViewControllerclass]]) {

//獲取點擊的行

NSIntegerselectedRow = [self.tableViewindexPathForSelectedRow].row;

ChatViewController*chatVc = destVC;

chatVc.buddy=self.boddyList[selectedRow];

}

}

3).聊天控制器(ChatViewController)中發(fā)送消息代碼如下

#pragma mark -UITextViewDelegate

-(void)textViewDidChange:(UITextView*)textView{

//監(jiān)聽Send事件--判斷最后的一個字符是不是換行字符(因為點擊send時,textfield會換行)

if([textView.texthasSuffix:@"\n"]) {

NSLog(@"發(fā)送操作");

[selfsendMessage:textView.text];

//清空textView的文字

textView.text=nil;

}

}

//發(fā)送消息

-(void)sendMessage:(NSString*)text{

//把最后一個換行字符去除

#warning換行字符只占用一個長度

text = [textsubstringToIndex:text.length-1];

//消息=消息頭+消息體

#warning每一種消息類型對象不同的消息體

//EMTextMessageBody:文字

//EMImageMessageBody:圖片

//EMLocationMessageBody:位置

//EMVoiceMessageBody:語音

//EMVideoMessageBody:視頻

//EMFileMessageBody:文件

//EMCmdMessageBody:透傳

//1.創(chuàng)建文字消息體

EMTextMessageBody*body = [[EMTextMessageBodyalloc]initWithText:text];

NSString*from = [[EMClientsharedClient]currentUsername];

//2.生成Message消息對象

EMMessage*message = [[EMMessagealloc]initWithConversationID:self.buddyfrom:fromto:self.buddybody:bodyext:nil];

message.chatType=EMChatTypeChat;//設(shè)置為單聊消息

//消息類型為:

//EMChatTypeChat:設(shè)置為單聊消息

// EMChatTypeGroupChat:設(shè)置為群聊消息

//EMChatTypeChatRoom:設(shè)置為聊天室消息

//3.發(fā)送消息

//發(fā)送所有類型的消息都用這個接口,只是消息類型不同

[[EMClientsharedClient].chatManagersendMessage:messageprogress:^(intprogress) {

}completion:^(EMMessage*message,EMError*error) {

NSLog(@"完成消息發(fā)送%@",error);

}];

// 4.把消息添加到數(shù)據(jù)源传睹,然后再刷新表格(發(fā)送完消息立即顯示)

[self.dataSourcesaddObject:message];

[self.tableViewreloadData];

// 5.把消息顯示在頂部(發(fā)送完消息自動滾動到鍵盤頂部)

[selfscrollToBottom];

}

-(void)scrollToBottom{

//1.獲取最后一行

if(self.dataSources.count==0) {

return;

}

NSIndexPath*lastIndex = [NSIndexPathindexPathForRow:self.dataSources.count-1inSection:0];

[self.tableViewscrollToRowAtIndexPath:lastIndexatScrollPosition:UITableViewScrollPositionBottomanimated:YES];

}

18.聊天界面-添加本地聊天記錄

1).在聊天控制器中的viewdidload方法中添加當(dāng)前navigation的title為好友的名字,加載本地聊天記錄

//顯示好友的名字

self.title=self.buddy;

//加載本地數(shù)據(jù)庫聊天記錄(MessageV1)

[selfloadLocalChatRecords];

-(void)loadLocalChatRecords{

//要獲取本地聊天記錄使用會話對象

//獲取一個會話

//EMConversationTypeChat單聊會話

//EMConversationTypeGroupChat群聊會話

//EMConversationTypeChatRoom聊天室會話

EMConversation*conversation = [[EMClientsharedClient].chatManagergetConversation:self.buddytype:EMConversationTypeChatcreateIfNotExist:YES];

//加載與當(dāng)前聊天用戶所有聊天記錄

// fromUser:若傳好友名字,則只會加載好友發(fā)的聊天記錄,若為nil加載兩方的

longlongtimestamp = [[NSDatedate]timeIntervalSince1970] *1000+1;

[conversationloadMessagesWithType:EMMessageBodyTypeTexttimestamp:timestampcount:100fromUser:nilsearchDirection:EMMessageSearchDirectionUpcompletion:^(NSArray*aMessages,EMError*aError) {

//aMessages內(nèi)部為EMMessage對象

//添加到數(shù)據(jù)源

[self.dataSourcesaddObjectsFromArray:aMessages];

[self.tableViewreloadData];

}];

}

2).在自定義cellChatCell中添加外部模型屬性耳幢,并實現(xiàn)set方法,封裝

/**消息模型欧啤,內(nèi)部set方法顯示文字*/

@property(nonatomic,strong)EMMessage*message;

-(void)setMessage:(EMMessage*)message{

_message= message;

// 1.獲取消息體

idbody = message.body;

if([bodyisKindOfClass:[EMTextMessageBodyclass]]) {//文本消息

EMTextMessageBody*textBody = body;

self.chatLabel.text= textBody.text;

}elseif([bodyisKindOfClass:[EMVoiceMessageBodyclass]]){//語音消息

self.chatLabel.text=@"【語音】";

}

else{

self.chatLabel.text=@"未知類型";

}

}

3).在聊天控制器中修改tableview的數(shù)據(jù)源方法

-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{

returnself.dataSources.count;

}

-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{

//設(shè)置label的數(shù)據(jù)

NSLog(@"%@",self.dataSources[indexPath.row]);

// 1.獲取消息模型

EMMessage*msg =self.dataSources[indexPath.row];

self.chatCellTool.message= msg;

return[self.chatCellToolcellHeghit];

}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{

//1.先獲取消息模型

EMMessage*message =self.dataSources[indexPath.row];

ChatCell*cell =nil;

if([message.fromisEqualToString:self.buddy]) {//接收方

cell = [tableViewdequeueReusableCellWithIdentifier:ReceiverCell];

}else{//發(fā)送方

cell = [tableViewdequeueReusableCellWithIdentifier:SenderCell];

}

//顯示內(nèi)容

cell.message= message;

returncell;

}

29.聊天界面-監(jiān)聽消息回復(fù)(將對方發(fā)的消息及時顯示在當(dāng)前聊天界面)

聊天控制器中的viewdidload中設(shè)置聊天管理器代理并遵守協(xié)議EMChatManagerDelegate

[[EMClientsharedClient].chatManageraddDelegate:selfdelegateQueue:nil];

//實現(xiàn)代理方法

#pragma mark -EMChatManagerDelegate

//收到一條以上消息

- (void)messagesDidReceive:(NSArray*)aMessages{

for(EMMessage*messageinaMessages) {

#warning from一定等于當(dāng)前聊天用戶才可以刷新數(shù)據(jù)(當(dāng)test1 - test7兩者聊天時睛藻,test8發(fā)過來的消息不能顯示在該聊天記錄界面)

if([message.fromisEqualToString:self.buddy]) {

//1.把接收的消息添加到數(shù)據(jù)源

[self.dataSourcesaddObject:message];

//2.刷新表格

[self.tableViewreloadData];

//3.顯示數(shù)據(jù)到底部

[selfscrollToBottom];

}

}

}

20.完善聊天輸入框

實現(xiàn)輸入框自動改變高度:

1).找到mainstoryboard中的聊天控制器界面的ChatInputToolBar找到他的高度屬性,并拖線到聊天控制器成為其屬性

@property(weak,nonatomic)IBOutletNSLayoutConstraint*inputbarHeightConstant;

2).在聊天控制器ChatViewController中的監(jiān)聽文字改變的方法中添加:

#pragma mark -UITextViewDelegate

-(void)textViewDidChange:(UITextView*)textView{

//監(jiān)視textView.contentOffset的變化

NSLog(@"contentOffset %@",NSStringFromCGPoint(textView.contentOffset));

// 1.計算TextView的高度邢隧,調(diào)整整個intputbar的高度

CGFloattextViewH =0;

CGFloatminHeight =33;//textView最小的高度

CGFloatmaxHeight =68;//textView最大的高度

//獲取contentSize的高度(因為textView繼承自scrollview)

CGFloatcontentHeight = textView.contentSize.height;

if(contentHeight < minHeight) {

textViewH = minHeight;

}elseif(contentHeight > maxHeight){

textViewH = maxHeight;

}else{

textViewH = contentHeight;

}

// 2.監(jiān)聽Send事件--判斷最后的一個字符是不是換行字符(因為點擊send時店印,textfield會換行)

if([textView.texthasSuffix:@"\n"]) {

NSLog(@"發(fā)送操作");

[selfsendMessage:textView.text];

//清空textView的文字

textView.text=nil;

//發(fā)送時,textViewH的高度為33

textViewH = minHeight;

}

// 3.調(diào)整整個InputToolBar高度

self.inputbarHeightConstant.constant=6+7+ textViewH;

//加個動畫

[UIViewanimateWithDuration:0.25animations:^{

[self.viewlayoutIfNeeded];

}];

// 4.記光標(biāo)回到原位

#warning技巧

[textViewsetContentOffset:CGPointZeroanimated:YES];

[textViewscrollRangeToVisible:textView.selectedRange];

}

3).給textview添加背景:

在textview后面加一個背景圖片(imageview)倒慧,在mainstoryboard中找到ChatInputToolBar按摘,往里面拖一個imageview包券,設(shè)置其約束與textview一樣,添加背景圖片(并設(shè)置拉伸效果)炫贤,將textView的背景色改為透明

21.發(fā)送語音

1).點擊左邊的話筒按鈕溅固,輸入框變?yōu)榘l(fā)語音框,自動布局

在mainstoryboard中的聊天控制器界面的ChatInputToolBar中拖一個button兰珍,直接蓋住textView上面侍郭,修改文字為“按住說話”,修改高亮?xí)r的文字為“松開發(fā)送”掠河,設(shè)置約束亮元,固定高度,選擇默認為隱藏口柳,拖線監(jiān)聽左邊的話筒按鈕:

//語音框

@property(weak,nonatomic)IBOutletUIButton*recordBtn;

//監(jiān)聽語音點擊按鈕

- (IBAction)voiceAction:(id)sender {

//1.顯示錄音按鈕

self.recordBtn.hidden= !self.recordBtn.hidden;

self.textView.hidden= !self.textView.hidden;

}

2).到環(huán)信官方demo中EaseUI-中找到DeviceHelper導(dǎo)入框架,EaseLocalDefine.h/EaseUIResource.bundle也導(dǎo)入框架

推進項目的Lib文件苹粟。再改控制器中導(dǎo)入頭文件#import"EMCDDeviceManager.h"

拖線監(jiān)聽語音框,監(jiān)聽按下去時跃闹,動作(選中該按鈕嵌削,),找到點下觸發(fā)望艺,拖線監(jiān)聽:

#pragma mark按鈕點下去開始錄音

//開始錄音

- (IBAction)beginVoiceAction:(id)sender {

//文件名以時間命名(根據(jù)時間定義文件的名字)

//filename:錄音將要存放的文件(自動存放沙盒)

intx =arc4random() %100000;

NSTimeIntervaltime = [[NSDatedate]timeIntervalSince1970];

NSString*fileName = [NSStringstringWithFormat:@"%d%d",(int)time,x];

NSLog(@"按鈕點下去開始錄音");

//這個方法苛秕,就是那個框架(DeviceHelper)中的方法

[[EMCDDeviceManagersharedInstance]asyncStartRecordingWithFileName:fileNamecompletion:^(NSError*error) {

if(!error) {

NSLog(@"開始錄音成功");

}

}];

}

#pragma mark手指從按鈕范圍內(nèi)松開結(jié)束錄音

//結(jié)束錄音

- (IBAction)endVoiceAction:(id)sender {

[[EMCDDeviceManagersharedInstance]asyncStopRecordingWithCompletion:^(NSString*recordPath,NSIntegeraDuration,NSError*error) {

//recordPath:錄音的路徑

//aDuration:錄音的時長

if(!error) {

NSLog(@"錄音成功");

NSLog(@"%@",recordPath);

//發(fā)送語音給服務(wù)器

[selfsendVoice:recordPathduration:aDuration];

}else{

NSLog(@"== %@",error);

}

}];

}

#pragma mark手指從按鈕外面松開取消錄音

//取消錄音

- (IBAction)cancelVoiceAction:(id)sender {

[[EMCDDeviceManagersharedInstance]cancelCurrentRecording];

}

#pragma mark發(fā)送語音消息

//發(fā)送語音

-(void)sendVoice:(NSString*)recordPath duration:(NSInteger)duration{

//1.創(chuàng)建語音消息體

EMVoiceMessageBody*body = [[EMVoiceMessageBodyalloc]initWithLocalPath:recordPathdisplayName:@"語音"];

body.duration= (int)duration;

NSString*from = [[EMClientsharedClient]currentUsername];

//2.生成voice消息對象

EMMessage*voice = [[EMMessagealloc]initWithConversationID:self.buddyfrom:fromto:self.buddybody:bodyext:nil];

voice.chatType=EMChatTypeChat;//設(shè)置為單聊消息

//3.發(fā)送消息

//發(fā)送所有類型的消息都用這個接口,只是消息類型不同

[[EMClientsharedClient].chatManagersendMessage:voiceprogress:^(intprogress) {

}completion:^(EMMessage*message,EMError*error) {

NSLog(@"完成消息發(fā)送%@",error);

}];

// 4.把消息添加到數(shù)據(jù)源,然后再刷新表格(發(fā)送完消息立即顯示)

[self.dataSourcesaddObject:voice];

[self.tableViewreloadData];

// 5.把消息顯示在頂部(發(fā)送完消息自動滾動到鍵盤頂部)

[selfscrollToBottom];

}

22.播放語音

1).//顯示語音的形式為圖片加文字找默,在ChatCell中實現(xiàn)方法:

#pragma mark返回語音富文本

-(NSAttributedString*)voiceAtt{

//創(chuàng)建一個可變的富文本

NSMutableAttributedString*voiceAttM = [[NSMutableAttributedStringalloc]init];

// 1.接收方:富文本=圖片+時間

if([self.reuseIdentifierisEqualToString:ReceiverCell]) {

// 1.1接收方的語音圖片

UIImage*receiverImg = [UIImageimageNamed:@"chat_receiver_audio_playing_full"];

// 1.2創(chuàng)建圖片附件

NSTextAttachment*imgAttachment = [[NSTextAttachmentalloc]init];

imgAttachment.image= receiverImg;

imgAttachment.bounds=CGRectMake(0, -7,30,30);

// 1.3圖片富文本

NSAttributedString*imgAtt = [NSAttributedStringattributedStringWithAttachment:imgAttachment];

[voiceAttMappendAttributedString:imgAtt];

// 1.4.創(chuàng)建時間富文本

//獲取時間

EMVoiceMessageBody*voiceBody = (EMVoiceMessageBody*)self.message.body;

NSIntegerduration = voiceBody.duration;

NSString*timeStr = [NSStringstringWithFormat:@"%ld'",duration];

NSAttributedString*timeAtt = [[NSAttributedStringalloc]initWithString:timeStr];

[voiceAttMappendAttributedString:timeAtt];

}else{

// 2.發(fā)送方:富文本=時間+圖片

// 2.1拼接時間

//獲取時間

EMVoiceMessageBody*voiceBody = (EMVoiceMessageBody*)self.message.body;

NSIntegerduration = voiceBody.duration;

NSString*timeStr = [NSStringstringWithFormat:@"%ld'",duration];

NSAttributedString*timeAtt = [[NSAttributedStringalloc]initWithString:timeStr];

[voiceAttMappendAttributedString:timeAtt];

// 2.1拼接圖片

UIImage*receiverImg = [UIImageimageNamed:@"chat_sender_audio_playing_full"];

//創(chuàng)建圖片附件

NSTextAttachment*imgAttachment = [[NSTextAttachmentalloc]init];

imgAttachment.image= receiverImg;

imgAttachment.bounds=CGRectMake(0, -7,30,30);

//圖片富文本

NSAttributedString*imgAtt = [NSAttributedStringattributedStringWithAttachment:imgAttachment];

[voiceAttMappendAttributedString:imgAtt];

}

return[voiceAttMcopy];

}

2).在該方法中該setMessage:(EMMessage*)message:

self.chatLabel.text = @"【語音】";

self.chatLabel.attributedText= [selfvoiceAtt];

3).給語音消息添加點擊手勢艇劫,并監(jiān)聽方法:(在mainstoryboard中找到,消息label打開用戶交互)

//導(dǎo)入頭文件:#import"EMCDDeviceManager.h"#import"AudioPlayTool.h"

-(void)awakeFromNib{

//在此方法做一些初始化操作

// 1.給label添加敲擊手勢

UITapGestureRecognizer*tap = [[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(messageLabelTap:)];

[self.chatLabeladdGestureRecognizer:tap];

}

#pragma mark messagelabel點擊的觸發(fā)方法

-(void)messageLabelTap:(UITapGestureRecognizer*)recognizer{

NSLog(@"%s",__func__);

//播放語音

//只有當(dāng)前的類型是為語音的時候才播放

//1.獲取消息體

idbody =self.message.body;

if([bodyisKindOfClass:[EMVoiceMessageBodyclass]]) {

NSLog(@"播放語音");

BOOLreceiver = [self.reuseIdentifierisEqualToString:ReceiverCell];

[AudioPlayToolplayWithMessage:self.messagemsgLabel:self.chatLabelreceiver:receiver];

}

}

4).寫一個工具類來播放語音goup –chart-Tool-AudioPlayTool

#import

#import"EMSDK.h"

@interfaceAudioPlayTool :NSObject

+(void)playWithMessage:(EMMessage*)msg msgLabel:(UILabel*)msgLabel receiver:(BOOL)receiver;

@end

#import"AudioPlayTool.h"

#import"EMCDDeviceManager.h"

//用imageview播放動畫(好好研究)

staticUIImageView*animatingImageView;//正在執(zhí)行動畫的ImageView

@implementationAudioPlayTool

+(void)playWithMessage:(EMMessage*)msg msgLabel:(UILabel*)msgLabel receiver:(BOOL)receiver{

//把以前的動畫移除

[animatingImageViewstopAnimating];

[animatingImageViewremoveFromSuperview];

//1.播放語音

//獲取語音路徑

EMVoiceMessageBody*voiceBody = (EMVoiceMessageBody*) msg.body;

// localPath:本地音頻路徑

// remotePath:服務(wù)器音頻路徑

//本地語音文件路徑

NSString*path = voiceBody.localPath;

//如果本地語音文件不存在惩激,使用服務(wù)器語音

NSFileManager*manager = [NSFileManagerdefaultManager];

if(![managerfileExistsAtPath:path]) {

path = voiceBody.remotePath;

}

//播放語音

[[EMCDDeviceManagersharedInstance]asyncPlayingWithPath:pathcompletion:^(NSError*error) {

NSLog(@"語音播放完成%@",error);

//移除動畫

[animatingImageViewstopAnimating];

[animatingImageViewremoveFromSuperview];

}];

//2.添加動畫(點擊語音消息時有動畫)讓UIImageView播放動畫店煞、動畫的內(nèi)部實現(xiàn)為圖片的輪播

//2.1創(chuàng)建一個UIImageView添加到Label上

UIImageView*imgView = [[UIImageViewalloc]init];

[msgLabeladdSubview:imgView];

//2.2添加動畫圖片

if(receiver) {

imgView.animationImages=@[[UIImageimageNamed:@"chat_receiver_audio_playing000"],

[UIImageimageNamed:@"chat_receiver_audio_playing001"],

[UIImageimageNamed:@"chat_receiver_audio_playing002"],

[UIImageimageNamed:@"chat_receiver_audio_playing003"]];

imgView.frame=CGRectMake(0,0,30,30);

}else{

imgView.animationImages=@[[UIImageimageNamed:@"chat_sender_audio_playing_000"],

[UIImageimageNamed:@"chat_sender_audio_playing_001"],

[UIImageimageNamed:@"chat_sender_audio_playing_002"],

[UIImageimageNamed:@"chat_sender_audio_playing_003"]];

imgView.frame=CGRectMake(msgLabel.bounds.size.width-30,0,30,30);

}

imgView.animationDuration=1;

[imgViewstartAnimating];

animatingImageView= imgView;

}

@end

5).//解決bug:當(dāng)輸入多行文字時,再點語音按鈕风钻,此時的textView欄不恢復(fù)原來高度顷蟀,則:

在聊天控制器XMGChatViewController中的

//監(jiān)聽語音點擊按鈕

- (IBAction)voiceAction:(id)sender {

// 1.顯示錄音按鈕

self.recordBtn.hidden= !self.recordBtn.hidden;

if(self.recordBtn.hidden==NO) {//錄音按鈕要顯示

//InputToolBar的高度要回來默認(46);

self.inputbarHeightConstant.constant=46;

//隱藏鍵盤

[self.viewendEditing:YES];

}else{

//當(dāng)不錄音的時候,鍵盤顯示

[self.textViewbecomeFirstResponder];

//恢復(fù)InputToolBar高度(輸入幾行文字骡技,點擊語音按鈕鸣个,再點會文字按鈕,textView高度不變)

[selftextViewDidChange:self.textView];

}

}

23.發(fā)送圖片顯示圖片

A.發(fā)送圖片

1).點擊輸入框的右邊的+按鈕布朦,到相冊選擇圖片

拖線到聊天控制器中監(jiān)聽方法:

- (IBAction)showImgPickerAction:(id)sender {

//顯示圖片選擇的控制器

UIImagePickerController*imgPicker = [[UIImagePickerControlleralloc]init];

//設(shè)置源

imgPicker.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;

imgPicker.delegate=self;

[selfpresentViewController:imgPickeranimated:YEScompletion:NULL];

/**用戶選中圖片的回調(diào)(代理方法)*/

-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

//1.獲取用戶選中的圖片

UIImage*selectedImg =info[UIImagePickerControllerOriginalImage];

//2.發(fā)送圖片

[selfsendImg:selectedImg];

//3.隱藏當(dāng)前圖片選擇控制器

[selfdismissViewControllerAnimated:YEScompletion:NULL];

}

}

#pragma mark發(fā)送圖片

-(void)sendImg:(UIImage*)selectedImg{

//1.構(gòu)造圖片消息體

/*

*第一個參數(shù):原始大小的圖片對象1000 * 1000

*第二個參數(shù):縮略圖的圖片對象120 * 120

*/

//將image轉(zhuǎn)化為data

NSData*imageData =UIImagePNGRepresentation(selectedImg);

EMImageMessageBody*body = [[EMImageMessageBodyalloc]initWithData:imageDatathumbnailData:nil];

NSString*from = [[EMClientsharedClient]currentUsername];

//2.生成image消息對象

EMMessage*imageMessage = [[EMMessagealloc]initWithConversationID:self.buddyfrom:fromto:self.buddybody:bodyext:nil];

imageMessage.chatType=EMChatTypeChat;//設(shè)置為單聊消息

//3.發(fā)送消息

//發(fā)送所有類型的消息都用這個接口,只是消息類型不同

[[EMClientsharedClient].chatManagersendMessage:imageMessageprogress:^(intprogress) {

}completion:^(EMMessage*message,EMError*error) {

NSLog(@"完成消息發(fā)送%@",error);

}];

// 4.把消息添加到數(shù)據(jù)源囤萤,然后再刷新表格(發(fā)送完消息立即顯示)

[self.dataSourcesaddObject:imageMessage];

[self.tableViewreloadData];

// 5.把消息顯示在頂部(發(fā)送完消息自動滾動到鍵盤頂部)

[selfscrollToBottom];

}

2).抽取方法(把發(fā)送文本的方法名改為sendText,由于發(fā)文本、圖片是趴、語音都有這一個段代碼涛舍,因此抽成一個方法)

-(void)sendMessage:(EMMessageBody*)body{

//1.生成Message消息對象

NSString*from = [[EMClientsharedClient]currentUsername];

EMMessage*message = [[EMMessagealloc]initWithConversationID:self.buddyfrom:fromto:self.buddybody:bodyext:nil];

message.chatType=EMChatTypeChat;//設(shè)置為單聊消息

//消息類型為:

//EMChatTypeChat:設(shè)置為單聊消息

// EMChatTypeGroupChat:設(shè)置為群聊消息

//EMChatTypeChatRoom:設(shè)置為聊天室消息

//2.發(fā)送消息

//發(fā)送所有類型的消息都用這個接口,只是消息類型不同

[[EMClientsharedClient].chatManagersendMessage:messageprogress:^(intprogress) {

}completion:^(EMMessage*message,EMError*error) {

NSLog(@"完成消息發(fā)送%@",error);

}];

// 3.把消息添加到數(shù)據(jù)源,然后再刷新表格(發(fā)送完消息立即顯示)

[self.dataSourcesaddObject:message];

[self.tableViewreloadData];

// 4.把消息顯示在頂部(發(fā)送完消息自動滾動到鍵盤頂部)

[selfscrollToBottom];

}

B.顯示圖片

拖入SDWebImage框架唆途,導(dǎo)入#import"UIImageView+WebCache.h"

在ChatCell做盅。M文件中-(void)setMessage:(EMMessage*)message的方法中

添加elseif([bodyisKindOfClass:[EMImageMessageBodyclass]]){//圖片消息

[selfshowImage]; }

-(void)showImage{

//獲取圖片消息體

EMImageMessageBody*imgBody = (EMImageMessageBody*)self.message.body;

CGRectthumbnailFrm = (CGRect){0,0,imgBody.thumbnailSize};

//設(shè)置Label的尺寸足夠顯示UIImageView

NSTextAttachment*imgAttach = [[NSTextAttachmentalloc]init];

imgAttach.bounds= thumbnailFrm;

NSAttributedString*imgAtt = [NSAttributedStringattributedStringWithAttachment:imgAttach];

self.chatLabel.attributedText= imgAtt;

//1.cell里添加一個UIImageView

[self.messageLabel addSubview:self.chatImgView];

//2.設(shè)置圖片控件為縮略圖的尺寸

self.chatImgView.frame= thumbnailFrm;

//3.下載圖片

NSLog(@"thumbnailLocalPath %@",imgBody.thumbnailLocalPath);

NSLog(@"thumbnailRemotePath %@",imgBody.thumbnailRemotePath);

NSFileManager*manager = [NSFileManagerdefaultManager];

//如果本地圖片存在缤削,直接從本地顯示圖片

UIImage*palceImg = [UIImageimageNamed:@"downloading"];

if([managerfileExistsAtPath:imgBody.thumbnailLocalPath]) {

#warning本地路徑使用fileURLWithPath方法,網(wǎng)絡(luò)路徑使用URLWithString:

[self.chatImgViewsd_setImageWithURL:[NSURLfileURLWithPath:imgBody.thumbnailLocalPath]placeholderImage:palceImg];

}else{

//如果本地圖片不存吹榴,從網(wǎng)絡(luò)加載圖片

[self.chatImgViewsd_setImageWithURL:[NSURLURLWithString:imgBody.thumbnailRemotePath]placeholderImage:palceImg];

}

}

C.修改bug

1).圖片cell會重用亭敢,重用的時候應(yīng)該講圖片移除;在XMGChatCell中添加

添加屬性

/**聊天圖片控件*/

@property(nonatomic,strong)UIImageView*chatImgView;

-(UIImageView*)chatImgView{

if(!_chatImgView) {

_chatImgView= [[UIImageViewalloc]init];

}

return_chatImgView;

}

-(void)setMessage:(EMMessage *)message{

//重用時图筹,把聊天圖片控件移除

[self.chatImgView removeFromSuperview];

滑動聊天控制器時不能在播放語音:

在AudioPlayTool中添加方法

+(void)stop;

+(void)stop{

//停止播放語音

[[EMCDDeviceManagersharedInstance]stopPlaying];

//移除動畫

[animatingImageViewstopAnimating];

[animatingImageViewremoveFromSuperview];

}

在聊天控制器中調(diào)用:

-(void)scrollViewWillBeginDragging:(UIScrollView*)scrollView{

//停止語音播放

[AudioPlayToolstop];

}

24.顯示時間的cell

時間顯示的規(guī)則

同一分中內(nèi)的消息帅刀,只顯示一個時間

/*

15:52

msg1 15:52:10

msg2 15:52:08

msg2 15:52:02

*/

/*今天:時:分(HH:mm)

*昨天:昨天+時+分(昨天HH:mm)

*昨天以前:(前天)年:月:日時分(2015-09-26 15:27)

*/

在mainstoryboard中的聊天控制器中拖一個時間cell,拖一個label自動布局远剩,自定義cell(TimeCell)為該類扣溺,并將label拖線為屬性。設(shè)置重用標(biāo)識瓜晤。

分析:數(shù)據(jù)源數(shù)組中不僅有模型對象锥余,也有時間字符串對象,因此痢掠,在數(shù)據(jù)源實現(xiàn)cell方法中驱犹,導(dǎo)入TimeCell頭文件添加

//判斷數(shù)據(jù)源類型

if([self.dataSources[indexPath.row]isKindOfClass:[NSStringclass]]) {//顯示時間cell

XMGTimeCell*timeCell = [tableViewdequeueReusableCellWithIdentifier:@"TimeCell"];

timeCell.timeLabel.text=self.dataSources[indexPath.row];

returntimeCell;

}

在cell高度數(shù)據(jù)源方法中設(shè)置時間cell的高度

//時間cell的高度是固定

if([self.dataSources[indexPath.row]isKindOfClass:[NSStringclass]]) {

return18;

}

25.顯示時間的計算

新建一個時間計算工具類,繼承自nsobject(思想牛逼)

#import

@interfaceTimeTool : NSObject

//時間戳

+(NSString *)timeStr:(longlong)timestamp;

@end

#import"TimeTool.h"

@implementationTimeTool

+(NSString *)timeStr:(longlong)timestamp{

//返回時間格式

//currentDate 2015-09-28 16:28:09 +0000

//msgDate 2015-09-28 10:36:22 +0000

NSCalendar*calendar =[NSCalendar currentCalendar];

//1.獲取當(dāng)前的時間

NSDate *currentDate = [NSDate date];

//獲取年足画,月雄驹,日

NSDateComponents *components = [calendarcomponents:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:currentDate];

NSInteger currentYear = components.year;

NSInteger currentMonth = components.month;

NSInteger currentDay = components.day;

NSLog(@"currentYear

%ld",components.year);

NSLog(@"currentMonth

%ld",components.month);

NSLog(@"currentDay

%ld",components.day);

//2.獲取消息發(fā)送時間

NSDate *msgDate = [NSDate dateWithTimeIntervalSince1970:timestamp/1000.0];

//獲取年,月淹辞,日

components = [calendarcomponents:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDayfromDate:msgDate];

CGFloat msgYead = components.year;

CGFloat msgMonth = components.month;

CGFloat msgDay = components.day;

NSLog(@"msgYear

%ld",components.year);

NSLog(@"msgMonth

%ld",components.month);

NSLog(@"msgDay

%ld",components.day);

//3.判斷:

/*今天:(HH:mm)

*昨天: (昨天HH:mm)

*昨天以前:(2015-09-26 15:27)

*/

NSDateFormatter *dateFmt = [[NSDateFormatter alloc] init];

if(currentYear == msgYead

&& currentMonth == msgMonth

&& currentDay == msgDay) {//今天

dateFmt.dateFormat=@"HH:mm";

}elseif(currentYear == msgYead

&& currentMonth == msgMonth

&& currentDay -1== msgDay){//昨天

dateFmt.dateFormat=@"昨天HH:mm";

}else{//昨天以前

dateFmt.dateFormat=@"yyy-MM-dd

HH:mm";

}

return[dateFmt stringFromDate:msgDate];

}

@end

由于datasource數(shù)組需要判斷什么時間添加模型医舆,什么時間添加時間字符串因此寫一個獨立的方法:在聊天控制器中修改

/**當(dāng)前添加的時間*/

@property(nonatomic,copy)NSString*currentTimeStr;

-(void)addDataSourcesWithMessage:(EMMessage*)msg{

// 1.判斷EMMessage對象前面是否要加"時間"

//if (self.dataSources.count == 0) {

////long long timestamp = ([[NSDate date] timeIntervalSince1970] - 60 * 60 *24 * 2) * 1000;

//

//}

NSString*timeStr = [XMGTimeTooltimeStr:msg.timestamp];

if(![self.currentTimeStrisEqualToString:timeStr]) {

[self.dataSourcesaddObject:timeStr];

self.currentTimeStr= timeStr;

}

// 2.再加EMMessage

[self.dataSourcesaddObject:msg];

}

修改加載數(shù)據(jù)方法:

-(void)loadLocalChatRecords{

//假設(shè)在數(shù)組的第一位置添加時間

//[self.dataSources addObject:@"16:06"];

//要獲取本地聊天記錄使用會話對象

EMConversation*conversation = [[EaseMobsharedInstance].chatManagerconversationForChatter:self.buddy.usernameconversationType:eConversationTypeChat];

//加載與當(dāng)前聊天用戶所有聊天記錄

NSArray*messages = [conversationloadAllMessages];

//for (id obj in messages) {

//NSLog(@"%@",[obj class]);

//}

//添加到數(shù)據(jù)源

//[self.dataSources addObjectsFromArray:messages];

for(EMMessage*msgObjinmessages) {

[selfaddDataSourcesWithMessage:msgObj];

}

}

修改聊天控制器中添加數(shù)據(jù)源數(shù)組方法:

-(void)sendMessage:(id)body{

[selfaddDataSourcesWithMessage:msgObj];

-(void)didReceiveMessage:(EMMessage*)message{

//1.把接收的消息添加到數(shù)據(jù)源

//[self.dataSources addObject:message];

[selfaddDataSourcesWithMessage:message];

27.顯示歷史會話記錄(就是顯示給誰聊過天)

在會話控制器XMGConversationViewController中

/**歷史會話記錄*/

@property(nonatomic,strong)NSArray*conversations;

viewDidLoad添加:

//添加聊天管理者代理

[[EMClientsharedClient].chatManageraddDelegate:selfdelegateQueue:nil];

//獲取歷史會話記錄

[selfloadConversations];

-(void)loadConversations{

//獲取歷史會話記錄

//1.從內(nèi)存中獲取歷史回話記錄,獲取內(nèi)存中所有會話

//獲取所有會話,如果內(nèi)存中不存在會從DB中加載

NSArray*conversations = [[EMClientsharedClient].chatManagergetAllConversations];

NSLog(@"zzzzzzz %@",conversations);

self.conversations= conversations;

//顯示總的未讀數(shù)

[selfshowTabBarBadge];

}

-(void)showTabBarBadge{

//遍歷所有的會話記錄象缀,將未讀取的消息數(shù)進行累

NSIntegertotalUnreadCount =0;

for(EMConversation*conversationinself.conversations) {

totalUnreadCount += [conversationunreadMessagesCount];

}

self.navigationController.tabBarItem.badgeValue= [NSStringstringWithFormat:@"%ld",totalUnreadCount];

}

在mainstoryboard中找到會話控制器蔬将,設(shè)置cell的重用標(biāo)識,cell的style為subtitle

在會話控制器中實現(xiàn)數(shù)據(jù)源方法

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {

returnself.conversations.count;

}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{

staticNSString*ID =@"ConversationCell";

UITableViewCell*cell = [tableViewdequeueReusableCellWithIdentifier:ID];

//獲取會話模型

EMConversation*conversaion =self.conversations[indexPath.row];

//顯示數(shù)據(jù)

// 1.顯示用戶名

cell.textLabel.text= [NSStringstringWithFormat:@"%@ ====未讀消息數(shù):%zd",conversaion.conversationId,conversaion.unreadMessagesCount];

// 2.顯示最新的一條記錄

//獲取消息體

idbody = conversaion.latestMessage.body;

if([bodyisKindOfClass:[EMTextMessageBodyclass]]) {

EMTextMessageBody*textBody = body;

cell.detailTextLabel.text= textBody.text;

}elseif([bodyisKindOfClass:[EMVoiceMessageBodyclass]]){

EMVoiceMessageBody*voiceBody = body;

cell.detailTextLabel.text= [voiceBodydisplayName];

}elseif([bodyisKindOfClass:[EMImageMessageBodyclass]]){

EMImageMessageBody*imgBody = body;

cell.detailTextLabel.text= imgBody.displayName;

}else{

cell.detailTextLabel.text=@"未知消息類型";

}

returncell;

}

實現(xiàn)一些代理方法:

#pragma mark - EMChatManagerDelegate

//會話列表發(fā)生變化調(diào)用

- (void)conversationListDidUpdate:(NSArray*)aConversationList{

//給數(shù)據(jù)源重新賦值

self.conversations= aConversationList;

//刷新表格

[self.tableViewreloadData];

//顯示總的未讀數(shù)

[selfshowTabBarBadge];

}

//收到消息

//一旦接受到消息,刷新未讀消息列表

-(void)messagesDidReceive:(NSArray*)aMessages{

//更新表格

[self.tableViewreloadData];

//顯示總的未讀數(shù)

[selfshowTabBarBadge];

}

27.設(shè)置消息為已讀

點擊會話界面的cell,會跳到聊天控制器

導(dǎo)入聊天控制器頭文件

在mainstoryboard中聊天控制器中設(shè)置storyboardIDChatPage

-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{

//進入到聊天控制器

//1.從storybaord加載聊天控制器

ChatViewController*chatVc = [[UIStoryboardstoryboardWithName:@"Main"bundle:nil]instantiateViewControllerWithIdentifier:@"ChatPage"];

//會話

EMConversation*conversation =self.conversations[indexPath.row];

//2.設(shè)置好友屬性

chatVc.buddy= conversation.conversationId;

//3.展現(xiàn)聊天界面

[self.navigationControllerpushViewController:chatVcanimated:YES];

}

到聊天控制器中設(shè)置消息為已讀

添加一個屬性

/**當(dāng)前會話對象*/

@property(nonatomic,strong)EMConversation*conversation;

-(void)loadLocalChatRecords{

self.conversation= conversation;

-(void)addDataSourcesWithMessage:(EMMessage*)msg{

// 3.設(shè)置消息為已讀取

//將消息設(shè)置為已讀

//aMessageId要設(shè)置消息的ID

//pError錯誤信息

[self.conversationmarkMessageAsReadWithId:msg.messageIderror:nil];

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末央星,一起剝皮案震驚了整個濱河市霞怀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌等曼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凿蒜,死亡現(xiàn)場離奇詭異禁谦,居然都是意外死亡,警方通過查閱死者的電腦和手機废封,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門州泊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漂洋,你說我怎么就攤上這事遥皂×ε纾” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵演训,是天一觀的道長弟孟。 經(jīng)常有香客問我,道長样悟,這世上最難降的妖魔是什么拂募? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮窟她,結(jié)果婚禮上陈症,老公的妹妹穿的比我還像新娘。我一直安慰自己震糖,他們只是感情好录肯,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吊说,像睡著了一般论咏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疏叨,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天潘靖,我揣著相機與錄音,去河邊找鬼蚤蔓。 笑死卦溢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秀又。 我是一名探鬼主播单寂,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吐辙!你這毒婦竟也來了宣决?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤昏苏,失蹤者是張志新(化名)和其女友劉穎尊沸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贤惯,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡洼专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了孵构。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屁商。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颈墅,靈堂內(nèi)的尸體忽然破棺而出蜡镶,到底是詐尸還是另有隱情雾袱,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布官还,位于F島的核電站芹橡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妻枕。R本人自食惡果不足惜僻族,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屡谐。 院中可真熱鬧述么,春花似錦、人聲如沸愕掏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饵撑。三九已至剑梳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滑潘,已是汗流浹背垢乙。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留语卤,地道東北人追逮。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像粹舵,于是被迫代替她去往敵國和親钮孵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 概述在iOS開發(fā)中UITableView可以說是使用最廣泛的控件眼滤,我們平時使用的軟件中到處都可以看到它的影子巴席,類似...
    liudhkk閱讀 8,987評論 3 38
  • 1.badgeVaule氣泡提示 2.git終端命令方法> pwd查看全部 >cd>ls >之后桌面找到文件夾內(nèi)容...
    i得深刻方得S閱讀 4,631評論 1 9
  • 上官網(wǎng)注冊賬號 首先來到環(huán)信的官網(wǎng),然后登陸.沒有賬號先注冊一個. 進去之后創(chuàng)建應(yīng)用,如圖 創(chuàng)建應(yīng)用界面 點擊確定...
    loneWolf01閱讀 500評論 0 0
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,124評論 29 470
  • 看路上 那些 大大小小 緩慢爬行的“海爬狗” 看江上 那些 層層疊疊 穿梭往來的“浪里白” 看街上 那些 花花綠綠...
    聞丁閱讀 521評論 3 1