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

互联网 17-2-15
  聊天界面的效果图如下:在下面的聊天界面中中用到了3类cell,一类是显示文字和表情的,一类是显示录音的,一类是显示图片的。当点击图片时会跳转到另一个Controller中来进行图片显示,在图片显示页面中添加了一个捏合的手势。点击播放按钮,会播放录制的音频,cell的大学会根据内容的多少来调整,而cell中textView的高度是通过约束来设置的。

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

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

#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计算出text的宽高        CGRect bound = [self.attrString boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil];           //根据text的宽高来重新设置新的约束      //背景的宽      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];            //设置图片      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,通过block回调把图片传到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,点击cell上的button,播放对应的录音,代码如下:

#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(@"播放错误:%@",[error description]);      }      self.audioPlayer = player;      [self.audioPlayer play];  }  @end

二,cell搞定后要实现我们的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;    //工具栏的高约束,用于当输入文字过多时改变工具栏的约束  @property (strong, nonatomic) NSLayoutConstraint *tooViewConstraintHeight;    //存放所有的cell中的内容  @property (strong, nonatomic) NSMutableArray *dataSource;    //storyBoard上的控件  @property (strong, nonatomic) IBOutlet UITableView *myTableView;    //用户类型  @property (assign, nonatomic) UserType userType;    //从相册获取图片  @property (strong, nonatomic) UIImagePickerController *imagePiceker;    @end

实现工具栏中的回调的代码如下,通过Block,工具栏和ViewController交互

//实现工具栏的回调  -(void)setToolViewBlock  {      __weak __block ChatViewController *copy_self = self;      //通过block回调接收到toolView中的text      [self.toolView setMyTextBlock:^(NSString *myText) {          NSLog(@"%@",myText);                    [copy_self sendMessage:SendText Content:myText];      }];                  //回调输入框的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];      }];            //录音取消(录音取消后,把音量图片进行隐藏)      [self.toolView setCancelRecordBlock:^(int flag) {          if (flag == 1) {              copy_self.volumeImageView.hidden = YES;          }      }];                  //扩展功能回调      [self.toolView setExtendFunctionBlock:^(int buttonTag) {          switch (buttonTag) {              case 1:                  //从相册获取                  [copy_self presentViewController:copy_self.imagePiceker animated:YES completion:^{                                        }];                  break;              case 2:                  //拍照                  break;                                default:                  break;          }      }];  }

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

//发送消息  -(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];           }

根据ToolView中回调接口,获取工具栏中textView的ContentSize,通过ContentSize来调整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];      }  }

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

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

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

//显示表情,用属性字符串显示表情  -(NSMutableAttributedString *)showFace:(NSString *)str  {      //加载plist文件中的数据      NSBundle *bundle = [NSBundle mainBundle];      //寻找资源的路径      NSString *path = [bundle pathForResource:@"emoticons" ofType:@"plist"];      //获取plist中的数据      NSArray *face = [[NSArray alloc] initWithContentsOfFile:path];            //创建一个可变的属性字符串            NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];            UIFont *baseFont = [UIFont systemFontOfSize:17];      [attributeString addAttribute:NSFontAttributeName value:baseFont                         range:NSMakeRange(0, str.length)];            //正则匹配要替换的文字的范围      //正则表达式      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]);      }            //通过正则表达式来匹配字符串      NSArray *resultArray = [re matchesInString:str options:0 range:NSMakeRange(0, str.length)];                  //用来存放字典,字典中存储的是图片和图片对应的位置      NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];            //根据匹配范围来用图片进行相应的替换      for(NSTextCheckingResult *match in resultArray) {          //获取数组元素中得到range          NSRange range = [match range];                    //获取原字符串中对应的值          NSString *subStr = [str substringWithRange:range];                    for (int i = 0; i < face.count; i ++)          {              if ([face[i][@"chs"] isEqualToString:subStr])              {                                    //face[i][@"gif"]就是我们要加载的图片                  //新建文字附件来存放我们的图片                  NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];                                    //给附件添加图片                  textAttachment.image = [UIImage imageNamed:face[i][@"png"]];                                    //把附件转换成可变字符串,用于替换掉源字符串中的表情文字                  NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];                                    //把图片和图片对应的位置存入字典中                  NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];                  [imageDic setObject:imageStr forKey:@"image"];                  [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];                                    //把字典存入数组中                  [imageArray addObject:imageDic];                                }          }      }            //从后往前替换      for (int i = imageArray.count -1; i >= 0; i--)      {          NSRange range;          [imageArray[i][@"range"] getValue:&range];          //进行替换          [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];                }            return  attributeString;  }

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

//调整cell的高度  -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath  {            //根据文字计算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;   }

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

//设置cell  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  {      //根据类型选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;  }

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

//发送图片的放大  -(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];          }

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

//键盘出来的时候调整tooView的位置  -(void) keyChange:(NSNotification *) notify  {      NSDictionary *dic = notify.userInfo;                  CGRect endKey = [dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];      //坐标系的转换      CGRect endKeySwap = [self.view convertRect:endKey fromView:self.view.window];      //运动时间      [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];      }];  }

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

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

更多iOS开发之微信聊天页面实现 相关文章请关注PHP中文网!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: 自动布局
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:mysql保存emoji表情(微信开发用户昵称..)

相关资讯