频道栏目
首页 > 资讯 > 微信公众平台开发 > 正文

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

16-08-16        来源:[db:作者]  
收藏   我要投稿

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

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

#FormatImgID_0#

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

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

#FormatImgID_1##FormatImgID_2#

1 #import "TextCell.h"

2

3 @interface TextCell()

4

5 @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;

11

12 @end

13

14 @implementation TextCell

15

16 -(void)setCellValue:(NSMutableAttributedString *)str

17 {

18 //移除约束

19 [self removeConstraint:_chatBgImageWidthConstraint];

20 [self removeConstraint:_chatTextWidthConstaint];

21

22 self.attrString = str;

23 NSLog(@"%@",self.attrString);

24

25 //由text计算出text的宽高

26 CGRect bound = [self.attrString boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

27

28 //根据text的宽高来重新设置新的约束

29 //背景的宽

30 NSString *widthImageString;

31 NSArray *tempArray;

32

33 widthImageString = [NSString stringWithFormat:@"H:[_chatBgImageView(%f)]", bound.size.width+45];

34 tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0 metrics:0 views:NSDictionaryOfVariableBindings(_chatBgImageView)];

35 _chatBgImageWidthConstraint = tempArray[0];

36 [self addConstraint:self.chatBgImageWidthConstraint];

37

38 widthImageString = [NSString stringWithFormat:@"H:[_chatTextView(%f)]", bound.size.width+20];

39 tempArray = [NSLayoutConstraint constraintsWithVisualFormat:widthImageString options:0 metrics:0 views:NSDictionaryOfVariableBindings(_chatTextView)];

40 _chatBgImageWidthConstraint = tempArray[0];

41 [self addConstraint:self.chatBgImageWidthConstraint];

42

43 //设置图片

44 UIImage *image = [UIImage imageNamed:@"chatfrom_bg_normal.png"];

45 image = [image resizableImageWithCapInsets:(UIEdgeInsetsMake(image.size.height * 0.6, image.size.width * 0.4, image.size.height * 0.3, image.size.width * 0.4))];

46

47 //image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];

48

49

50

51 [self.chatBgImageView setImage:image];

52

53 self.chatTextView.attributedText = str;

54

55

56 }

57

58 @end

View Code

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

#FormatImgID_3##FormatImgID_4#

1 #import "MyImageCell.h"

2

3 @interface MyImageCell()

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;

8

9 @end

10

11 @implementation MyImageCell

12

13 -(void)setCellValue:(UIImage *)sendImage

14 {

15 self.buttonImage = sendImage;

16 UIImage *image = [UIImage imageNamed:@"chatto_bg_normal.png"];

17 image = [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];

20

21 }

22

23 -(void)setButtonImageBlock:(ButtonImageBlock)block

24 {

25 self.imageBlock = block;

26 }

27

28 - (IBAction)tapImageButton:(id)sender {

29 self.imageBlock(self.buttonImage);

30 }

31

32 @end

View Code

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

#FormatImgID_5##FormatImgID_6#

1 #import "VoiceCellTableViewCell.h"

2

3 @interface VoiceCellTableViewCell()

4

5 @property (strong, nonatomic) NSURL *playURL;

6 @property (strong, nonatomic) AVAudioPlayer *audioPlayer;

7

8 @end

9

10 @implementation VoiceCellTableViewCell

11

12 -(void)setCellValue:(NSDictionary *)dic

13 {

14 _playURL = dic[@"body"][@"content"];

15 }

16

17 - (IBAction)tapVoiceButton:(id)sender {

18

19

20 NSError *error = nil;

21 AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:_playURL error:&error];

22 if (error) {

23 NSLog(@"播放错误:%@",[error description]);

24 }

25 self.audioPlayer = player;

26 [self.audioPlayer play];

27 }

28 @end

View Code

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

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

#FormatImgID_7##FormatImgID_8#

1 //枚举Cell类型

2 typedef enum : NSUInteger {

3 SendText,

4 SendVoice,

5 SendImage

6 } MySendContentType;

7

8

9 //枚举用户类型

10 typedef enum : NSUInteger {

11 MySelf,

12 MyFriend

13 } UserType;

14

15 @interface ChatViewController ()

16

17 //工具栏

18 @property (nonatomic,strong) ToolView *toolView;

19

20 //音量图片

21 @property (strong, nonatomic) UIImageView *volumeImageView;

22

23 //工具栏的高约束,用于当输入文字过多时改变工具栏的约束

24 @property (strong, nonatomic) NSLayoutConstraint *tooViewConstraintHeight;

25

26 //存放所有的cell中的内容

27 @property (strong, nonatomic) NSMutableArray *dataSource;

28

29 //storyBoard上的控件

30 @property (strong, nonatomic) IBOutlet UITableView *myTableView;

31

32 //用户类型

33 @property (assign, nonatomic) UserType userType;

34

35 //从相册获取图片

36 @property (strong, nonatomic) UIImagePickerController *imagePiceker;

37

38 @end

View Code

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

#FormatImgID_9##FormatImgID_10#

1 //实现工具栏的回调

2 -(void)setToolViewBlock

3 {

4 __weak __block ChatViewController *copy_self = self;

5 //通过block回调接收到toolView中的text

6 [self.toolView setMyTextBlock:^(NSString *myText) {

7 NSLog(@"%@",myText);

8

9 [copy_self sendMessage:SendText Content:myText];

10 }];

11

12

13 //回调输入框的contentSize,改变工具栏的高度

14 [self.toolView setContentSizeBlock:^(CGSize contentSize) {

15 [copy_self updateHeight:contentSize];

16 }];

17

18

19 //获取录音声量,用于声音音量的提示

20 [self.toolView setAudioVolumeBlock:^(CGFloat volume) {

21

22 copy_self.volumeImageView.hidden = NO;

23 int index = (int)(volume*100)%6+1;

24 [copy_self.volumeImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"record_animate_%02d.png",index]]];

25 }];

26

27 //获取录音地址(用于录音播放方法)

28 [self.toolView setAudioURLBlock:^(NSURL *audioURL) {

29 copy_self.volumeImageView.hidden = YES;

30

31 [copy_self sendMessage:SendVoice Content:audioURL];

32 }];

33

34 //录音取消(录音取消后,把音量图片进行隐藏)

35 [self.toolView setCancelRecordBlock:^(int flag) {

36 if (flag == 1) {

37 copy_self.volumeImageView.hidden = YES;

38 }

39 }];

40

41

42 //扩展功能回调

43 [self.toolView setExtendFunctionBlock:^(int buttonTag) {

44 switch (buttonTag) {

45 case 1:

46 //从相册获取

47 [copy_self presentViewController:copy_self.imagePiceker animated:YES completion:^{

48

49 }];

50 break;

51 case 2:

52 //拍照

53 break;

54

55 default:

56 break;

57 }

58 }];

59 }

View Code

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

#FormatImgID_11##FormatImgID_12#

1 //发送消息

2 -(void)sendMessage:(MySendContentType) sendType Content:(id)content

3 {

4

5 //把收到的url封装成字典

6 UserType userType = self.userType;

7

8 NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:2];

9 [tempDic setValue:@(userType) forKey:@"userType"];

10

11 NSDictionary *bodyDic = @{@"type":@(sendType),

12 @"content":content};

13 [tempDic setValue:bodyDic forKey:@"body"];

14 [self.dataSource addObject:tempDic];

15

16 //重载tableView

17 [self.myTableView reloadData];

18

19 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.dataSource.count-1 inSection:0];

20

21 [self.myTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

22

23

24 }

View Code

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

#FormatImgID_13##FormatImgID_14#

1 //更新toolView的高度约束

2 -(void)updateHeight:(CGSize)contentSize

3 {

4 float height = contentSize.height + 18;

5 if (height <= 80) {

6 [self.view removeConstraint:self.tooViewConstraintHeight];

7

8 NSString *string = [NSString stringWithFormat:@"V:[_toolView(%f)]", height];

9

10 NSArray * tooViewConstraintV = [NSLayoutConstraint constraintsWithVisualFormat:string options:0 metrics:0 views:NSDictionaryOfVariableBindings(_toolView)];

11 self.tooViewConstraintHeight = tooViewConstraintV[0];

12 [self.view addConstraint:self.tooViewConstraintHeight];

13 }

14 }

View Code

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

#FormatImgID_15##FormatImgID_16#

1 //获取图片后要做的方法

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

3 {

4 UIImage *pickerImage = info[UIImagePickerControllerEditedImage];

5

6 //发送图片

7 [self sendMessage:SendImage Content:pickerImage];

8

9 [self dismissViewControllerAnimated:YES completion:^{}];

10

11 }

12

13 -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

14 {

15 //在ImagePickerView中点击取消时回到原来的界面

16 [self dismissViewControllerAnimated:YES completion:^{}];

17 }

View Code

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

#FormatImgID_17##FormatImgID_18#

1 //显示表情,用属性字符串显示表情

2 -(NSMutableAttributedString *)showFace:(NSString *)str

3 {

4 //加载plist文件中的数据

5 NSBundle *bundle = [NSBundle mainBundle];

6 //寻找资源的路径

7 NSString *path = [bundle pathForResource:@"emoticons" ofType:@"plist"];

8 //获取plist中的数据

9 NSArray *face = [[NSArray alloc] initWithContentsOfFile:path];

10

11 //创建一个可变的属性字符串

12

13 NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];

14

15 UIFont *baseFont = [UIFont systemFontOfSize:17];

16 [attributeString addAttribute:NSFontAttributeName value:baseFont

17 range:NSMakeRange(0, str.length)];

18

19 //正则匹配要替换的文字的范围

20 //正则表达式

21 NSString * pattern = @"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]";

22 NSError *error = nil;

23 NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];

24

25 if (!re) {

26 NSLog(@"%@", [error localizedDescription]);

27 }

28

29 //通过正则表达式来匹配字符串

30 NSArray *resultArray = [re matchesInString:str options:0 range:NSMakeRange(0, str.length)];

31

32

33 //用来存放字典,字典中存储的是图片和图片对应的位置

34 NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];

35

36 //根据匹配范围来用图片进行相应的替换

37 for(NSTextCheckingResult *match in resultArray) {

38 //获取数组元素中得到range

39 NSRange range = [match range];

40

41 //获取原字符串中对应的值

42 NSString *subStr = [str substringWithRange:range];

43

44 for (int i = 0; i < face.count; i ++)

45 {

46 if ([face[i][@"chs"] isEqualToString:subStr])

47 {

48

49 //face[i][@"gif"]就是我们要加载的图片

50 //新建文字附件来存放我们的图片

51 NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];

52

53 //给附件添加图片

54 textAttachment.image = [UIImage imageNamed:face[i][@"png"]];

55

56 //把附件转换成可变字符串,用于替换掉源字符串中的表情文字

57 NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];

58

59 //把图片和图片对应的位置存入字典中

60 NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];

61 [imageDic setObject:imageStr forKey:@"image"];

62 [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];

63

64 //把字典存入数组中

65 [imageArray addObject:imageDic];

66

67 }

68 }

69 }

70

71 //从后往前替换

72 for (int i = imageArray.count -1; i >= 0; i--)

73 {

74 NSRange range;

75 [imageArray[i][@"range"] getValue:&range];

76 //进行替换

77 [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];

78

79 }

80

81 return attributeString;

82 }

View Code

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

#FormatImgID_19##FormatImgID_20#

1 //调整cell的高度

2 -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

3 {

4

5 //根据文字计算cell的高度

6 if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendText)]) {

7 NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];

8

9 CGRect textBound = [contentText boundingRectWithSize:CGSizeMake(150, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

10

11 float height = textBound.size.height + 40;

12 return height;

13 }

14 if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendVoice)])

15 {

16 return 73;

17 }

18

19 if ([self.dataSource[indexPath.row][@"body"][@"type"] isEqualToNumber:@(SendImage)])

20 {

21 return 125;

22 }

23

24 return 100;

25 }

View Code

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

#FormatImgID_21##FormatImgID_22#

1 //设置cell

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

3 {

4 //根据类型选cell

5 MySendContentType contentType = [self.dataSource[indexPath.row][@"body"][@"type"] integerValue];

6

7

8 if ([self.dataSource[indexPath.row][@"userType"] isEqual: @(MyFriend)]) {

9 switch (contentType) {

10 case SendText:

11 {

12 TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"textCell" forIndexPath:indexPath];

13 NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];

14 [cell setCellValue:contentText];

15 return cell;

16 }

17 break;

18

19 case SendImage:

20 {

21 heImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heImageCell" forIndexPath:indexPath];

22 [cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]];

23

24

25 __weak __block ChatViewController *copy_self = self;

26

27 //传出cell中的图片

28 [cell setButtonImageBlock:^(UIImage *image) {

29 [copy_self displaySendImage:image];

30 }];

31 return cell;

32 }

33 break;

34

35 case SendVoice:

36 {

37 VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"heVoiceCell" forIndexPath:indexPath];

38 [cell setCellValue:self.dataSource[indexPath.row]];

39 return cell;

40 }

41

42 break;

43

44 default:

45 break;

46 }

47

48 }

49

50

51 if ([self.dataSource[indexPath.row][@"userType"] isEqual: @(MySelf)]) {

52

53 switch (contentType) {

54 case SendText:

55 {

56 TextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myselfTextCell" forIndexPath:indexPath];

57 NSMutableAttributedString *contentText = [self showFace:self.dataSource[indexPath.row][@"body"][@"content"]];

58 [cell setCellValue:contentText];

59 return cell;

60 }

61 break;

62

63 case SendImage:

64 {

65 MyImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myImageCell" forIndexPath:indexPath];

66 [cell setCellValue:self.dataSource[indexPath.row][@"body"][@"content"]];

67

68 __weak __block ChatViewController *copy_self = self;

69

70 //传出cell中的图片

71 [cell setButtonImageBlock:^(UIImage *image) {

72 [copy_self displaySendImage:image];

73 }];

74

75

76 return cell;

77 }

78 break;

79

80 case SendVoice:

81 {

82 VoiceCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myVoiceCell" forIndexPath:indexPath];

83 [cell setCellValue:self.dataSource[indexPath.row]];

84 return cell;

85 }

86

87 break;

88

89 default:

90 break;

91 }

92 }

93 UITableViewCell *cell;

94 return cell;

95 }

View Code

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

#FormatImgID_23##FormatImgID_24#

1 //发送图片的放大

2 -(void) displaySendImage : (UIImage *)image

3 {

4 //把照片传到放大的controller中

5 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];

6

7 ImageViewController *imageController = [storyboard instantiateViewControllerWithIdentifier:@"imageController"];

8 [imageController setValue:image forKeyPath:@"image"];

9

10 [self.navigationController pushViewController:imageController animated:YES];

11

12

13 }

View Code

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

#FormatImgID_25##FormatImgID_26#

1 //键盘出来的时候调整tooView的位置

2 -(void) keyChange:(NSNotification *) notify

3 {

4 NSDictionary *dic = notify.userInfo;

5

6

7 CGRect endKey = [dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];

8 //坐标系的转换

9 CGRect endKeySwap = [self.view convertRect:endKey fromView:self.view.window];

10 //运动时间

11 [UIView animateWithDuration:[dic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{

12

13 [UIView setAnimationCurve:[dic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]];

14 CGRect frame = self.view.frame;

15

16 frame.size.height = endKeySwap.origin.y;

17

18 self.view.frame = frame;

19 [self.view layoutIfNeeded];

20 }];

21 }

View Code

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

#FormatImgID_27##FormatImgID_28#

1 - (IBAction)tapPichGesture:(id)sender {

2 UIPinchGestureRecognizer *gesture = sender;

3

4 //手势改变时

5 if (gesture.state == UIGestureRecognizerStateChanged)

6 {

7

8 //捏合手势中scale属性记录的缩放比例

9 self.myImageView.transform = CGAffineTransformMakeScale(gesture.scale, gesture.scale);

10 }

11

12 }

View Code

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

相关TAG标签
上一篇:[c#]asp.net开发微信公众平台(3)微信消息封装及反射赋值
下一篇:微信快速开发框架(四)-- 体验微信公众平台快速开发框架
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站