iOS开发之微信聊天页面实现

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

在上篇博客(iOS开发之微信聊天工具栏的封装)中对微信聊天页面下方的工具栏进行了封装,本篇博客中就使用之前封装的工具栏来进行聊天页面的编写。在聊天页面中主要用到了TableView的知识,还有如何在俩天中显示我们发送的表情,具体请参考之前的博客:IOS开发之显示微博表情,在这儿就不做赘述啦。在聊天页面用到了三对,六种Cell,不过cell的复杂度要比之前的新浪微博(IOS开发之新浪围脖)简单的多。废话少说吧,还是先来几张效果图,在给出实现代码吧。

聊天界面的效果图如下:在下面的聊天界面中中用到了3类cell,一类是显示文字和表情的,一类是显示录音的,一类是显示图片的。当点击图片时会跳转到另一个Controller中来进行图片显示,在图片显示页面中添加了一个捏合的手势(关于手势,请参考:iOS开发之手势识别)。点击播放按钮,会播放录制的音频,cell的大学会根据内容的多少来调整,而cell中textView的高度是通过约束来设置的。

一,定义我们要用的cell,代码如下:

1,显示表情和text的cell,代码如下,需要根据NSMutableAttributedString求出bound,然后改变cell上的ImageView和TextView的宽度的约束值,动态的调整气泡的大小,具体代码如下:

1#import"TextCell.h"23@interfaceTextCell()45@PRoperty (strong, nonatomic) IBOutlet UIImageView *headImageView;6@property (strong, nonatomic) IBOutlet UIImageView *chatBgImageView;7@property (strong, nonatomic) IBOutlet UITextView *chatTextView;8@property (strong, nonatomic) IBOutlet NSLayoutConstraint *chatBgImageWidthConstraint;9@property (strong, nonatomic) IBOutlet NSLayoutConstraint *chatTextWidthConstaint;10@property (strong, nonatomic) NSMutableAttributedString *attrString;1112@end1314@implementationTextCell1516-(void)setCellValue:(NSMutableAttributedString *)str17{18//移除约束19[self removeConstraint:_chatBgImageWidthConstraint];20[self removeConstraint:_chatTextWidthConstaint];2122self.attrString =str;23NSLog(@"%@",self.attrString);2425//由text计算出text的宽高26CGRect bound = [self.attrString boundingRectWithSize:CGSizeMake(150,1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil];2728//根据text的宽高来重新设置新的约束29//背景的宽30NSString *widthImageString;31NSArray *tempArray;3233widthImageString = [NSString stringWithFormat:@"H:[_chatBgImageView(%f)]", bound.size.width+45];34tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0metrics:0views:NSDictionaryOfVariableBindings(_chatBgImageView)];35_chatBgImageWidthConstraint = tempArray[0];36[self addConstraint:self.chatBgImageWidthConstraint];3738widthImageString = [NSString stringWithFormat:@"H:[_chatTextView(%f)]", bound.size.width+20];39tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0metrics:0views:NSDictionaryOfVariableBindings(_chatTextView)];40_chatBgImageWidthConstraint = tempArray[0];41[self addConstraint:self.chatBgImageWidthConstraint];4243//设置图片44UIImage *image = [UIImage imageNamed:@"chatfrom_bg_normal.png"];45image = [image resizableImageWithCapInsets:(UIEdgeInsetsMake(image.size.height *0.6, image.size.width *0.4, image.size.height *0.3, image.size.width *0.4))];4647//image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];48495051[self.chatBgImageView setImage:image];5253self.chatTextView.attributedText =str;545556}5758@end

View Code

2.显示图片的cell,通过block回调把图片传到Controller中,用于放大图片使用。

1#import"MyImageCell.h"23@interfaceMyImageCell()4@property (strong, nonatomic) IBOutlet UIImageView *bgImageView;5@property (strong, nonatomic) IBOutlet UIButton *imageButton;6@property (strong, nonatomic) ButtonImageBlock imageBlock;7@property (strong, nonatomic) UIImage *buttonImage;89@end1011@implementationMyImageCell1213-(void)setCellValue:(UIImage *)sendImage14{15self.buttonImage =sendImage;16UIImage *image = [UIImage imageNamed:@"chatto_bg_normal.png"];17image = [image resizableImageWithCapInsets:(UIEdgeInsetsMake(image.size.height *0.6, image.size.width *0.4, image.size.height *0.3, image.size.width *0.4))];18[self.bgImageView setImage:image];19[self.imageButton setImage:sendImage forState:UIControlStateNormal];2021}2223-(void)setButtonImageBlock:(ButtonImageBlock)block24{25self.imageBlock =block;26}2728- (IBAction)tapImageButton:(id)sender {29self.imageBlock(self.buttonImage);30}3132@end

View Code

3.显示录音的cell,点击cell上的button,播放对应的录音,代码如下:

1#import"VoiceCellTableViewCell.h"23@interfaceVoiceCellTableViewCell()45@property (strong, nonatomic) NSURL *playURL;6@property (strong, nonatomic) AVAudioPlayer *audioPlayer;78@end910@implementationVoiceCellTableViewCell1112-(void)setCellValue:(NSDictionary *)dic13{14_playURL = dic[@"body"][@"content"];15}1617- (IBAction)tapVoiceButton:(id)sender {181920NSError *error =nil;21AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:_playURL error:&error];22if(error) {23NSLog(@"播放错误:%@",[error description]);24}25self.audioPlayer =player;26[self.audioPlayer play];27}28@end

View Code

二,cell搞定后要实现我们的ChatController部分

1.ChatController.m中的延展和枚举代码如下:

1//枚举Cell类型2typedefenum: NSUInteger {3SendText,4SendVoice,5SendImage6} MySendContentType;789//枚举用户类型10typedefenum: NSUInteger {11MySelf,12MyFriend13} UserType;1415@interfaceChatViewController ()1617//工具栏18@property (nonatomic,strong) ToolView *toolView;1920//音量图片21@property (strong, nonatomic) UIImageView *volumeImageView;2223//工具栏的高约束,用于当输入文字过多时改变工具栏的约束24@property (strong, nonatomic) NSLayoutConstraint *tooViewConstraintHeight;2526//存放所有的cell中的内容27@property (strong, nonatomic) NSMutableArray *dataSource;2829//storyBoard上的控件30@property (strong, nonatomic) IBOutlet UITableView *myTableView;3132//用户类型33@property (assign, nonatomic) UserType userType;3435//从相册获取图片36@property (strong, nonatomic) UIImagePickerController *imagePiceker;3738@end

View Code

2.实现工具栏中的回调的代码如下,通过Block,工具栏和ViewController交互,具体ToolView的Block实现,请参考上一篇博客(iOS开发之微信聊天工具栏的封装),聊天工具栏使用代码如下:

1//实现工具栏的回调2-(void)setToolViewBlock3{4__weak __block ChatViewController *copy_self =self;5//通过block回调接收到toolView中的text6[self.toolView setMyTextBlock:^(NSString *myText) {7NSLog(@"%@",myText);89[copy_self sendMessage:SendText Content:myText];10}];111213//回调输入框的contentSize,改变工具栏的高度14[self.toolView setContentSizeBlock:^(CGSize contentSize) {15[copy_self updateHeight:contentSize];16}];171819//获取录音声量,用于声音音量的提示20[self.toolView setAudioVolumeBlock:^(CGFloat volume) {2122copy_self.volumeImageView.hidden =NO;23intindex = (int)(volume*100)%6+1;24[copy_self.volumeImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"record_animate_%02d.png",index]]];25}];2627//获取录音地址(用于录音播放方法)28[self.toolView setAudioURLBlock:^(NSURL *audioURL) {29copy_self.volumeImageView.hidden =YES;3031[copy_self sendMessage:SendVoice Content:audioURL];32}];3334//录音取消(录音取消后,把音量图片进行隐藏)35[self.toolView setCancelRecordBlock:^(intflag) {36if(flag ==1) {37copy_self.volumeImageView.hidden =YES;38}39}];404142//扩展功能回调43[self.toolView setExtendFunctionBlock:^(intbuttonTag) {44switch(buttonTag) {45case1:46//从相册获取47[copy_self presentViewController:copy_self.imagePiceker animated:YES completion:^{4849}];50

break;51case2:52//拍照53

break;5455default:56

break;57}58}];59}

View Code

3.把聊天工具栏中返回的内容显示在tableView中,代码如下:

1//发送消息2-(void)sendMessage:(MySendContentType) sendType Content:(id)content3{45//把收到的url封装成字典6UserType userType =self.userType;78NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:2];9[tempDic setValue:@(userType) forKey:@"userType"];1011NSDictionary *bodyDic = @{@"type":@(sendType),12@"content":content};13[tempDic setValue:bodyDic forKey:@"body"];14[self.dataSource addObject:tempDic];1516//重载tableView17[self.myTableView reloadData];1819NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.dataSource.count-1inSection:0];2021[self.myTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];222324}

View Code

4.根据ToolView中回调接口,获取工具栏中textView的ContentSize,通过ContentSize来调整ToolView的高度约束,代码如下:

1//更新toolView的高度约束2-(void)updateHeight:(CGSize)contentSize3{4floatheight = contentSize.height +18;5if(height <=80) {6[self.view removeConstraint:self.tooViewConstraintHeight];78NSString *string= [NSString stringWithFormat:@"V:[_toolView(%f)]", height];910NSArray * tooViewConstraintV = [NSLayoutConstraint constraintsWithVisualFormat:stringoptions:0metrics:0views:NSDictionaryOfVariableBindings(_toolView)];11self.tooViewConstraintHeight = tooViewConstraintV[0];12[self.view addConstraint:self.tooViewConstraintHeight];13}14}

View Code

5.从本地获取图片,并显示在相应的Cell上,代码如下:

1//获取图片后要做的方法2-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info3{4UIImage *pickerImage =info[UIImagePickerControllerEditedImage];56//发送图片7[self sendMessage:SendImage Content:pickerImage];89[self dismissViewControllerAnimated:YES completion:^{}];1011}1213-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker14{15//在ImagePickerView中点击取消时回到原来的界面16[self dismissViewControllerAnimated:YES completion:^{}];17}

View Code

6.把NSString 转换成NSMutableAttributeString,用于显示表情,代码如下:

1//显示表情,用属性字符串显示表情2-(NSMutableAttributedString *)showFace:(NSString *)str3{4//加载plist文件中的数据5NSBundle *bundle =[NSBundle mainBundle];6//寻找资源的路径7NSString *path = [bundle pathForResource:@"emoticons"ofType:@"plist"];8//获取plist中的数据9NSArray *face =[[NSArray alloc] initWithContentsOfFile:path];1011//创建一个可变的属性字符串1213NSMutableAttributedString *attributeString =[[NSMutableAttributedString alloc] initWithString:str];1415UIFont *baseFont = [UIFont systemFontOfSize:17];16[attributeString addAttribute:NSFontAttributeName value:baseFont17range:NSMakeRange(0, str.length)];1819//正则匹配要替换的文字的范围20//正则表达式21NSString * pattern =@"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]";22NSError *error =nil;23NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];2425if(!re) {26NSLog(@"%@", [error localizedDescription]);27}2829//通过正则表达式来匹配字符串30NSArray *resultArray = [re matchesInString:str options:0range:NSMakeRange(0, str.length)];313233//用来存放字典,字典中存储的是图片和图片对应的位置34NSMutableArray *imageArray =[NSMutableArray arrayWithCapacity:resultArray.count];3536//根据匹配范围来用图片进行相应的替换37for(NSTextCheckingResult *matchinresultArray) {38//获取数组元素中得到range39NSRange range =[match range];4041//获取原字符串中对应的值42NSString *subStr =[str substringWithRange:range];4344for(inti =0; i < face.count; i ++)45{46if([face[i][@"chs"] isEqualToString:subStr])47{4849//face[i][@"gif"]就是我们要加载的图片50//新建文字附件来存放我们的图片51NSTextAttachment *textAttachment =[[NSTextAttachment alloc] init];5253//给附件添加图片54textAttachment.image = [UIImage imageNamed:face[i][@"png"]];5556//把附件转换成可变字符串,用于替换掉源字符串中的表情文字57NSAttributedString *imageStr =[NSAttributedString attributedStringWithAttachment:textAttachment];5859//把图片和图片对应的位置存入字典中60NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];61[imageDic setObject:imageStr forKey:@"image"];62[imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];6364//把字典存入数组中65[imageArray addObject:imageDic];6667}68}69}7071//从后往前替换72for(inti = imageArray.count -1; i >=0; i--)73{74NSRange range;75[imageArray[i][@"range"] getValue:&range];76//进行替换77[attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];7879}8081returnattributeString;82}

View Code

7.根据Cell显示内容来调整Cell的高度,代码如下:

1//调整cell的高度2-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath3{45//根据文字计算cell的高度6if([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendText)]) {7NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];89CGRect textBound = [contentText boundingRectWithSize:CGSizeMake(150,1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil];1011floatheight = textBound.size.height +40;12returnheight;13}14if([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendVoice)])15{16return73;17}1819if([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendImage)])20{21return125;22}2324return100;25}

View Code

8.根据cell内容和用户类型,来选择Cell,代码如下:

1//设置cell2- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath3{4//根据类型选cell5MySendContentType contentType = [self.dataSource[indexPath.row][@"body"][@"type"] integerValue];678if([self.dataSource[indexPath.row][@"userType"] isEqual: @(MyFriend)]) {9switch(contentType) {10caseSendText:11{12TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"textCell"forIndexPath:indexPath];13NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];14[cell setCellValue:contentText];15returncell;16}17

break;1819caseSendImage:20{21heImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heImageCell"forIndexPath:indexPath];22[cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]];232425__weak __block ChatViewController *copy_self =self;2627//传出cell中的图片28[cell setButtonImageBlock:^(UIImage *image) {29[copy_self displaySendImage:image];30}];31returncell;32}33

break;3435caseSendVoice:36{37VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heVoiceCell"forIndexPath:indexPath];38[cell setCellValue:self.dataSource[indexPath.row]];39returncell;40}4142

break;4344default:45

break;46}4748}495051if([self.dataSource[indexPath.row][@"userType"] isEqual: @(MySelf)]) {5253switch(contentType) {54caseSendText:55{56TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myselfTextCell"forIndexPath:indexPath];57NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];58[cell setCellValue:contentText];59returncell;60}61

break;6263caseSendImage:64{65MyImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myImageCell"forIndexPath:indexPath];66[cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]];6768__weak __block ChatViewController *copy_self =self;6970//传出cell中的图片71[cell setButtonImageBlock:^(UIImage *image) {72[copy_self displaySendImage:image];73}];747576returncell;77}78

break;7980caseSendVoice:81{82VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myVoiceCell"forIndexPath:indexPath];83[cell setCellValue:self.dataSource[indexPath.row]];84returncell;85}8687

break;8889default:90

break;91}92}93UITableViewCell *cell;94returncell;95}

View Code

9.点击发送的图片来放大图片代码如下:

1//发送图片的放大2-(void) displaySendImage : (UIImage *)image3{4//把照片传到放大的controller中5UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main"bundle:[NSBundle mainBundle]];67ImageViewController *imageController = [storyboard instantiateViewControllerWithIdentifier:@"imageController"];8[imageController setValue:image forKeyPath:@"image"];910[self.navigationController pushViewController:imageController animated:YES];111213}

View Code

10.根据键盘的高度来调整ToolView的位置,代码如下:

1//键盘出来的时候调整tooView的位置2-(void) keyChange:(NSNotification *) notify3{4NSDictionary *dic =notify.userInfo;567CGRect endKey = [dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];8//坐标系的转换9CGRect endKeySwap =[self.view convertRect:endKey fromView:self.view.window];10//运动时间11[UIView animateWithDuration:[dic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{1213[UIView setAnimationCurve:[dic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]];14CGRect frame =self.view.frame;1516frame.size.height =endKeySwap.origin.y;1718self.view.frame =frame;19[self.view layoutIfNeeded];20}];21}

View Code

三,代码有点多,不过在关键的部分都加有注释,在图片显示View中通过捏合手势来调整图片的大小,代码如下:

1- (IBAction)tapPichGesture:(id)sender {2UIPinchGestureRecognizer *gesture =sender;34//手势改变时5if(gesture.state ==UIGestureRecognizerStateChanged)6{78//捏合手势中scale属性记录的缩放比例9self.myImageView.transform =CGAffineTransformMakeScale(gesture.scale, gesture.scale);10}1112}

View Code

上面的东西是在本地做的测试,没有加上XMPP即时通讯协议,以后的博客会通过服务器转发来进行聊天,并且会继续对微信进行完善,感兴趣的小伙伴继续关注吧。转载请注明出处。

Demo地址:https://github.com/lizelu/WeChat

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航