這篇文章主要介紹iOS開(kāi)發(fā)之微信聊天頁(yè)面怎么實(shí)現(xiàn) ,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
成都創(chuàng)新互聯(lián)是一家專業(yè)提供雙城企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、HTML5、小程序制作等業(yè)務(wù)。10年已為雙城眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。聊天界面的效果圖如下:在下面的聊天界面中中用到了3類cell,一類是顯示文字和表情的,一類是顯示錄音的,一類是顯示圖片的。當(dāng)點(diǎn)擊圖片時(shí)會(huì)跳轉(zhuǎn)到另一個(gè)Controller中來(lái)進(jìn)行圖片顯示,在圖片顯示頁(yè)面中添加了一個(gè)捏合的手勢(shì)。點(diǎn)擊播放按鈕,會(huì)播放錄制的音頻,cell的大學(xué)會(huì)根據(jù)內(nèi)容的多少來(lái)調(diào)整,而cell中textView的高度是通過(guò)約束來(lái)設(shè)置的。
一,定義我們要用的cell,代碼如下:
1,顯示表情和text的cell,代碼如下,需要根據(jù)NSMutableAttributedString求出bound,然后改變cell上的ImageView和TextView的寬度的約束值,動(dòng)態(tài)的調(diào)整氣泡的大小,具體代碼如下:
#import "TextCell.h" @interface TextCell() @property (strong, nonatomic) IBOutlet UIImageView *headImageView; @property (strong, nonatomic) IBOutlet UIImageView *chatBgImageView; @property (strong, nonatomic) IBOutlet UITextView *chatTextView; @property (strong, nonatomic) IBOutlet NSLayoutConstraint *chatBgImageWidthConstraint; @property (strong, nonatomic) IBOutlet NSLayoutConstraint *chatTextWidthConstaint; @property (strong, nonatomic) NSMutableAttributedString *attrString; @end @implementation TextCell -(void)setCellValue:(NSMutableAttributedString *)str { //移除約束 [self removeConstraint:_chatBgImageWidthConstraint]; [self removeConstraint:_chatTextWidthConstaint]; self.attrString = str; NSLog(@"%@",self.attrString); //由text計(jì)算出text的寬高 CGRect bound = [self.attrString boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; //根據(jù)text的寬高來(lái)重新設(shè)置新的約束 //背景的寬 NSString *widthImageString; NSArray *tempArray; widthImageString = [NSString stringWithFormat:@"H:[_chatBgImageView(%f)]", bound.size.width+45]; tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0 metrics:0 views:NSDictionaryOfVariableBindings(_chatBgImageView)]; _chatBgImageWidthConstraint = tempArray[0]; [self addConstraint:self.chatBgImageWidthConstraint]; widthImageString = [NSString stringWithFormat:@"H:[_chatTextView(%f)]", bound.size.width+20]; tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0 metrics:0 views:NSDictionaryOfVariableBindings(_chatTextView)]; _chatBgImageWidthConstraint = tempArray[0]; [self addConstraint:self.chatBgImageWidthConstraint]; //設(shè)置圖片 UIImage *image = [UIImage imageNamed:@"chatfrom_bg_normal.png"]; image = [image resizableImageWithCapInsets:(UIEdgeInsetsMake(image.size.height * 0.6, image.size.width * 0.4, image.size.height * 0.3, image.size.width * 0.4))]; //image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5]; [self.chatBgImageView setImage:image]; self.chatTextView.attributedText = str; } @end
2.顯示圖片的cell,通過(guò)block回調(diào)把圖片傳到Controller中,用于放大圖片使用。
#import "MyImageCell.h" @interface MyImageCell() @property (strong, nonatomic) IBOutlet UIImageView *bgImageView; @property (strong, nonatomic) IBOutlet UIButton *imageButton; @property (strong, nonatomic) ButtonImageBlock imageBlock; @property (strong, nonatomic) UIImage *buttonImage; @end @implementation MyImageCell -(void)setCellValue:(UIImage *)sendImage { self.buttonImage = sendImage; UIImage *image = [UIImage imageNamed:@"chatto_bg_normal.png"]; image = [image resizableImageWithCapInsets:(UIEdgeInsetsMake(image.size.height * 0.6, image.size.width * 0.4, image.size.height * 0.3, image.size.width * 0.4))]; [self.bgImageView setImage:image]; [self.imageButton setImage:sendImage forState:UIControlStateNormal]; } -(void)setButtonImageBlock:(ButtonImageBlock)block { self.imageBlock = block; } - (IBAction)tapImageButton:(id)sender { self.imageBlock(self.buttonImage); } @end
3.顯示錄音的cell,點(diǎn)擊cell上的button,播放對(duì)應(yīng)的錄音,代碼如下:
#import "VoiceCellTableViewCell.h" @interface VoiceCellTableViewCell() @property (strong, nonatomic) NSURL *playURL; @property (strong, nonatomic) AVAudioPlayer *audioPlayer; @end @implementation VoiceCellTableViewCell -(void)setCellValue:(NSDictionary *)dic { _playURL = dic[@"body"][@"content"]; } - (IBAction)tapVoiceButton:(id)sender { NSError *error = nil; AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:_playURL error:&error]; if (error) { NSLog(@"播放錯(cuò)誤:%@",[error description]); } self.audioPlayer = player; [self.audioPlayer play]; } @end
二,cell搞定后要實(shí)現(xiàn)我們的ChatController部分
ChatController.m中的延展和枚舉代碼如下:
//枚舉Cell類型 typedef enum : NSUInteger { SendText, SendVoice, SendImage } MySendContentType; //枚舉用戶類型 typedef enum : NSUInteger { MySelf, MyFriend } UserType; @interface ChatViewController () //工具欄 @property (nonatomic,strong) ToolView *toolView; //音量圖片 @property (strong, nonatomic) UIImageView *volumeImageView; //工具欄的高約束,用于當(dāng)輸入文字過(guò)多時(shí)改變工具欄的約束 @property (strong, nonatomic) NSLayoutConstraint *tooViewConstraintHeight; //存放所有的cell中的內(nèi)容 @property (strong, nonatomic) NSMutableArray *dataSource; //storyBoard上的控件 @property (strong, nonatomic) IBOutlet UITableView *myTableView; //用戶類型 @property (assign, nonatomic) UserType userType; //從相冊(cè)獲取圖片 @property (strong, nonatomic) UIImagePickerController *imagePiceker; @end
實(shí)現(xiàn)工具欄中的回調(diào)的代碼如下,通過(guò)Block,工具欄和ViewController交互
//實(shí)現(xiàn)工具欄的回調(diào) -(void)setToolViewBlock { __weak __block ChatViewController *copy_self = self; //通過(guò)block回調(diào)接收到toolView中的text [self.toolView setMyTextBlock:^(NSString *myText) { NSLog(@"%@",myText); [copy_self sendMessage:SendText Content:myText]; }]; //回調(diào)輸入框的contentSize,改變工具欄的高度 [self.toolView setContentSizeBlock:^(CGSize contentSize) { [copy_self updateHeight:contentSize]; }]; //獲取錄音聲量,用于聲音音量的提示 [self.toolView setAudioVolumeBlock:^(CGFloat volume) { copy_self.volumeImageView.hidden = NO; int index = (int)(volume*100)%6+1; [copy_self.volumeImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"record_animate_%02d.png",index]]]; }]; //獲取錄音地址(用于錄音播放方法) [self.toolView setAudioURLBlock:^(NSURL *audioURL) { copy_self.volumeImageView.hidden = YES; [copy_self sendMessage:SendVoice Content:audioURL]; }]; //錄音取消(錄音取消后,把音量圖片進(jìn)行隱藏) [self.toolView setCancelRecordBlock:^(int flag) { if (flag == 1) { copy_self.volumeImageView.hidden = YES; } }]; //擴(kuò)展功能回調(diào) [self.toolView setExtendFunctionBlock:^(int buttonTag) { switch (buttonTag) { case 1: //從相冊(cè)獲取 [copy_self presentViewController:copy_self.imagePiceker animated:YES completion:^{ }]; break; case 2: //拍照 break; default: break; } }]; }
把聊天工具欄中返回的內(nèi)容顯示在tableView中,代碼如下:
//發(fā)送消息 -(void)sendMessage:(MySendContentType) sendType Content:(id)content { //把收到的url封裝成字典 UserType userType = self.userType; NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:2]; [tempDic setValue:@(userType) forKey:@"userType"]; NSDictionary *bodyDic = @{@"type":@(sendType), @"content":content}; [tempDic setValue:bodyDic forKey:@"body"]; [self.dataSource addObject:tempDic]; //重載tableView [self.myTableView reloadData]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.dataSource.count-1 inSection:0]; [self.myTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }
根據(jù)ToolView中回調(diào)接口,獲取工具欄中textView的ContentSize,通過(guò)ContentSize來(lái)調(diào)整ToolView的高度約束,代碼如下:
//更新toolView的高度約束 -(void)updateHeight:(CGSize)contentSize { float height = contentSize.height + 18; if (height <= 80) { [self.view removeConstraint:self.tooViewConstraintHeight]; NSString *string = [NSString stringWithFormat:@"V:[_toolView(%f)]", height]; NSArray * tooViewConstraintV = [NSLayoutConstraint constraintsWithVisualFormat:string options:0 metrics:0 views:NSDictionaryOfVariableBindings(_toolView)]; self.tooViewConstraintHeight = tooViewConstraintV[0]; [self.view addConstraint:self.tooViewConstraintHeight]; } }
從本地獲取圖片,并顯示在相應(yīng)的Cell上,代碼如下:
//獲取圖片后要做的方法 -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *pickerImage = info[UIImagePickerControllerEditedImage]; //發(fā)送圖片 [self sendMessage:SendImage Content:pickerImage]; [self dismissViewControllerAnimated:YES completion:^{}]; } -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { //在ImagePickerView中點(diǎn)擊取消時(shí)回到原來(lái)的界面 [self dismissViewControllerAnimated:YES completion:^{}]; }
把NSString 轉(zhuǎn)換成NSMutableAttributeString,用于顯示表情,代碼如下:
//顯示表情,用屬性字符串顯示表情 -(NSMutableAttributedString *)showFace:(NSString *)str { //加載plist文件中的數(shù)據(jù) NSBundle *bundle = [NSBundle mainBundle]; //尋找資源的路徑 NSString *path = [bundle pathForResource:@"emoticons" ofType:@"plist"]; //獲取plist中的數(shù)據(jù) NSArray *face = [[NSArray alloc] initWithContentsOfFile:path]; //創(chuàng)建一個(gè)可變的屬性字符串 NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str]; UIFont *baseFont = [UIFont systemFontOfSize:17]; [attributeString addAttribute:NSFontAttributeName value:baseFont range:NSMakeRange(0, str.length)]; //正則匹配要替換的文字的范圍 //正則表達(dá)式 NSString * pattern = @"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]"; NSError *error = nil; NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error]; if (!re) { NSLog(@"%@", [error localizedDescription]); } //通過(guò)正則表達(dá)式來(lái)匹配字符串 NSArray *resultArray = [re matchesInString:str options:0 range:NSMakeRange(0, str.length)]; //用來(lái)存放字典,字典中存儲(chǔ)的是圖片和圖片對(duì)應(yīng)的位置 NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count]; //根據(jù)匹配范圍來(lái)用圖片進(jìn)行相應(yīng)的替換 for(NSTextCheckingResult *match in resultArray) { //獲取數(shù)組元素中得到range NSRange range = [match range]; //獲取原字符串中對(duì)應(yīng)的值 NSString *subStr = [str substringWithRange:range]; for (int i = 0; i < face.count; i ++) { if ([face[i][@"chs"] isEqualToString:subStr]) { //face[i][@"gif"]就是我們要加載的圖片 //新建文字附件來(lái)存放我們的圖片 NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; //給附件添加圖片 textAttachment.image = [UIImage imageNamed:face[i][@"png"]]; //把附件轉(zhuǎn)換成可變字符串,用于替換掉源字符串中的表情文字 NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment]; //把圖片和圖片對(duì)應(yīng)的位置存入字典中 NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2]; [imageDic setObject:imageStr forKey:@"image"]; [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"]; //把字典存入數(shù)組中 [imageArray addObject:imageDic]; } } } //從后往前替換 for (int i = imageArray.count -1; i >= 0; i--) { NSRange range; [imageArray[i][@"range"] getValue:&range]; //進(jìn)行替換 [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]]; } return attributeString; }
根據(jù)Cell顯示內(nèi)容來(lái)調(diào)整Cell的高度,代碼如下:
//調(diào)整cell的高度 -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { //根據(jù)文字計(jì)算cell的高度 if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendText)]) { NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]]; CGRect textBound = [contentText boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; float height = textBound.size.height + 40; return height; } if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendVoice)]) { return 73; } if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendImage)]) { return 125; } return 100; }
根據(jù)cell內(nèi)容和用戶類型,來(lái)選擇Cell,代碼如下:
//設(shè)置cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //根據(jù)類型選cell MySendContentType contentType = [self.dataSource[indexPath.row][@"body"][@"type"] integerValue]; if ([self.dataSource[indexPath.row][@"userType"] isEqual: @(MyFriend)]) { switch (contentType) { case SendText: { TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"textCell" forIndexPath:indexPath]; NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]]; [cell setCellValue:contentText]; return cell; } break; case SendImage: { heImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heImageCell" forIndexPath:indexPath]; [cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]]; __weak __block ChatViewController *copy_self = self; //傳出cell中的圖片 [cell setButtonImageBlock:^(UIImage *image) { [copy_self displaySendImage:image]; }]; return cell; } break; case SendVoice: { VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heVoiceCell" forIndexPath:indexPath]; [cell setCellValue:self.dataSource[indexPath.row]]; return cell; } break; default: break; } } if ([self.dataSource[indexPath.row][@"userType"] isEqual: @(MySelf)]) { switch (contentType) { case SendText: { TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myselfTextCell" forIndexPath:indexPath]; NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]]; [cell setCellValue:contentText]; return cell; } break; case SendImage: { MyImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myImageCell" forIndexPath:indexPath]; [cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]]; __weak __block ChatViewController *copy_self = self; //傳出cell中的圖片 [cell setButtonImageBlock:^(UIImage *image) { [copy_self displaySendImage:image]; }]; return cell; } break; case SendVoice: { VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myVoiceCell" forIndexPath:indexPath]; [cell setCellValue:self.dataSource[indexPath.row]]; return cell; } break; default: break; } } UITableViewCell *cell; return cell; }
點(diǎn)擊發(fā)送的圖片來(lái)放大圖片代碼如下:
//發(fā)送圖片的放大 -(void) displaySendImage : (UIImage *)image { //把照片傳到放大的controller中 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; ImageViewController *imageController = [storyboard instantiateViewControllerWithIdentifier:@"imageController"]; [imageController setValue:image forKeyPath:@"image"]; [self.navigationController pushViewController:imageController animated:YES]; }
根據(jù)鍵盤(pán)的高度來(lái)調(diào)整ToolView的位置,代碼如下:
//鍵盤(pán)出來(lái)的時(shí)候調(diào)整tooView的位置 -(void) keyChange:(NSNotification *) notify { NSDictionary *dic = notify.userInfo; CGRect endKey = [dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue]; //坐標(biāo)系的轉(zhuǎn)換 CGRect endKeySwap = [self.view convertRect:endKey fromView:self.view.window]; //運(yùn)動(dòng)時(shí)間 [UIView animateWithDuration:[dic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{ [UIView setAnimationCurve:[dic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]]; CGRect frame = self.view.frame; frame.size.height = endKeySwap.origin.y; self.view.frame = frame; [self.view layoutIfNeeded]; }]; }
代碼有點(diǎn)多,不過(guò)在關(guān)鍵的部分都加有注釋,在圖片顯示View中通過(guò)捏合手勢(shì)來(lái)調(diào)整圖片的大小,代碼如下:
- (IBAction)tapPichGesture:(id)sender { UIPinchGestureRecognizer *gesture = sender; //手勢(shì)改變時(shí) if (gesture.state == UIGestureRecognizerStateChanged) { //捏合手勢(shì)中scale屬性記錄的縮放比例 self.myImageView.transform = CGAffineTransformMakeScale(gesture.scale, gesture.scale); } }
以上是“iOS開(kāi)發(fā)之微信聊天頁(yè)面怎么實(shí)現(xiàn) ”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!