[iOS基础控件-6.9]聊天界面Demo

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

A.需求

做出一个类似于QQ、微信的聊天界面

1.每个cell包含发送时间、发送人(头像)、发送信息

2.使用对方头像放在左边,我方头像在右边

3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话框

4.隐藏相同的发送时间

5.底部功能按钮:语音按钮、消息输入框、表情按钮、附加按钮

6.响应键盘事件,呼出键盘、隐藏键盘时对上述的视图作出上移操作

7.键盘的发送事件处理

Code Source: https://github.com/hellovoidworld/ChatDemo

B.实现点

1.底层视图搭建

上部分聊天信息框:UITableView

下部分功能区:UIButton

信息输入框使用无边框,然后使用自带背景图片,以保证在不同版本的iOS中样式一致

2.构建框架

依照“微博展示”的代码框架,设计:

自定义message模型自定义cell装载了message模型和cell子控件位置尺寸的frame

3.使用扩展,给NSString加上文本size计算的功能

1@implementation NSString (Extension)23/** 测量文本的尺寸*/4- (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize {5NSDictionary *attrs =@{NSFontAttributeName: font};6CGSize size =[self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;78returnsize;9}1011@end

给信息文本框计算位置和尺寸

1//3.信息,尺寸可变2CGFloat screenWidth =[UIScreen mainScreen].bounds.size.width;3//3.1 设置最大尺寸4CGSize textMaxSize = CGSizeMake(screenWidth - iconWidth - padding *5, MAXFLOAT);5//3.2 计算真实尺寸6CGSize textRealSize =[message.text sizeWithFont:MESSAGE_TEXT_FONT maxSize:textMaxSize];78//3.3 调整信息的位置9CGFloat textX;10if(MessageTypeMe ==message.type) {11//我方,放在靠右12textX = CGRectGetMinX(_iconFrame) - textRealSize.width -padding;13}else{14//对方,放在靠左15textX = CGRectGetMaxX(_iconFrame) +padding;16}1718CGFloat textY =iconY;19_textFrame = CGRectMake(textX, textY, textRealSize.width, textRealSize.height);

4.使用数据中的信息类型,判断是我方发出的信息还是对方发出的信息,计算头像和信息的位置

1//2.头像2CGFloat iconWidth =40;3CGFloat iconHeight =40;45//2.1 根据信息的发送方调整头像位置6CGFloat iconX;7if(MessageTypeMe ==message.type) {8//我方,放在右边9iconX = [UIScreen mainScreen].bounds.size.width - padding -iconWidth;10}else{11//对方,放在左边12iconX =padding;13}1415CGFloat iconY = CGRectGetMaxY(_timeFrame) +padding;16_iconFrame = CGRectMake(iconX, iconY, iconWidth, iconHeight);

5.加上信息背景框

我方:使用蓝色背景聊天框

对方:使用白色背景聊天框

重点:图片的中心拉伸,利用图片分别水平、垂直方向某个区域进行拉伸,保持其他部分的图形 —>对UIImage使用扩展,返回具备了特定拉伸方式属性的图片

拉伸图片方式属性:

1@implementationUIImage (Extension)23+ (UIImage *) resizableImage:(NSString *) imageName {4UIImage *image =[UIImage imageNamed:imageName];5//取图片中部的1 x 1进行拉伸6UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height/2, image.size.width/2, image.size.height/2+1, image.size.width/2+1);7return[image resizableImageWithCapInsets:insets];8}910@end

设置图片:

1//3.1 设置聊天框2NSString *chatImageNormalName;3NSString *chatImageHighlightedName;4if(MessageTypeMe ==messageFrame.message.type) {5chatImageNormalName =@"chat_send_nor";6chatImageHighlightedName =@"chat_send_PRess_pic";7}else{8chatImageNormalName =@"chat_receive_nor";9chatImageHighlightedName =@"chat_receive_press_pic";10}1112UIImage *chatImageNormal =[UIImage resizableImage:chatImageNormalName];13UIImage *chatImageHighlighted =[UIImage resizableImage:chatImageHighlightedName];14[self.textView setBackgroundImage:chatImageNormal forState:UIControlStateNormal];15[self.textView setBackgroundImage:chatImageHighlighted forState:UIControlStateHighlighted];

6.调整信息文字内边距,让文字被“包裹”在聊天框内

1//3.2 调整文字的内边距2textView.contentEdgeInsets = UIEdgeInsetsMake(TEXT_INSET, TEXT_INSET, TEXT_INSET, TEXT_INSET);

因为背景图片边缘有空白,改变了文字内边距之后,高度会变高,需要对装载信息的view的frame尺寸做出相应改变:

1//3.信息,尺寸可变2CGFloat screenWidth =[UIScreen mainScreen].bounds.size.width;3//3.1 设置文本最大尺寸4CGSize textMaxSize = CGSizeMake(screenWidth - iconWidth - padding *10, MAXFLOAT);5//3.2 计算文本真实尺寸6CGSize textRealSize =[message.text sizeWithFont:MESSAGE_TEXT_FONT maxSize:textMaxSize];78//3.3 按钮尺寸9CGSize btnSize = CGSizeMake(textRealSize.width + TEXT_INSET*2, textRealSize.height + TEXT_INSET*2);1011//3.4 调整信息的位置12CGFloat textX;13if(MessageTypeMe ==message.type) {14//我方,放在靠右15textX = CGRectGetMinX(_iconFrame) - btnSize.width -padding;16}else{17//对方,放在靠左18textX = CGRectGetMaxX(_iconFrame) +padding;19}2021CGFloat textY =iconY;22_textFrame = CGRectMake(textX, textY, btnSize.width, btnSize.height);

7.屏蔽相同的发送时间

(1)在message模型中定义一个标志

1/** 是否隐藏发送时间*/2@property(nonatomic, assign) BOOL hideTime;

(2)当控制器从plist文件装载信息的时候初始化此标志

1//判断是否发送时间与上一条信息的发送时间相同,若是则不用显示了2MessageFrame *lastMessageFrame =[mdictArray lastObject];3if(lastMessageFrame &&[message.time isEqualToString:lastMessageFrame.message.time]) {4message.hideTime =YES;5}

(3)只有hideTime == NO,计算frame的时候,长期需要计算发送时间的frame

1//1.发送时间2if(NO ==message.hideTime) {3CGFloat timeWidth =[UIScreen mainScreen].bounds.size.width;4CGFloat timeHeight =40;5CGFloat timeX =0;6CGFloat timeY =0;7_timeFrame =CGRectMake(timeX, timeY, timeWidth, timeHeight);8}

8.响应键盘呼出缩回事件,上移或下移恢复整个版面(聊天区和功能区)

(1)设置控制器为键盘监听器

// 设置虚拟键盘监听器

1[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotificationobject:nil];

(2)编写监听方法

1/** 点击拖曳聊天区的时候,缩回键盘*/2- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {3//1.缩回键盘4[self.view endEditing:YES];5}678#pragmamark - 监听事件9- (void) keyboardWillChangeFrame:(NSNotification *) note {10//1.取得弹出后的键盘frame11CGRect keyboardFrame =[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];1213//2.键盘弹出的耗时时间14CGFloat duration =[note.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];1516//3.键盘变化时,view的位移,包括了上移/恢复下移17CGFloat transformY = keyboardFrame.origin.y -self.view.frame.size.height;1819[UIView animateWithDuration:duration animations:^{20self.view.transform = CGAffineTransformMakeTranslation(0, transformY);21}];222324}

9.设置数据框TextField,改变键盘

(1)当没有文字的时候禁用回车,设置回车样式

(2)调不出中文键盘

虽然在设置里面添加了中文键盘,但是依然找不到进入中文键盘的按钮

10.发送消息

(1)拖入信息输入框到控制器,设置控制器为输入框TextField的代理

1//设置信息输入框的代理2self.inputView.delegate= self;

(2)响应回车事件

1#pragmamark - TextField 代理方法2/** 回车响应事件*/3- (BOOL)textFieldShouldReturn:(UITextField *)textField {4//我方发出信息5[self sendMessageWithContent:textField.text andType:MessageTypeMe];67//自动回复8[self sendMessageWithContent:[NSString stringWithFormat:@"%@\n%@", textField.text,@"你妹!!!"] andType:MessageTypeOhter];910//消除消息框内容11self.inputView.text =nil;1213[self.tableView reloadData];1415//滚动到最新的消息16NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count -1inSection:0];17[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];1819returnYES;//返回值意义不明20}2122//发送消息23- (void) sendMessageWithContent:(NSString *) text andType:(MessageType) type {24//获取当前时间25NSDate *date =[NSDate date];26NSDateFormatter *formatter =[[NSDateFormatter alloc] init];27formatter.dateFormat =@"yyyy-MMM-dd hh:mm:ss";28NSString *dateStr =[formatter stringFromDate:date];2930//我方发出信息31NSDictionary *dict = @{@"text":text,32@"time":dateStr,33@"type":[NSString stringWithFormat:@"%d", type]};3435Message *message =[[Message alloc] init];36[message setValuesForKeysWithDictionary:dict];37MessageFrame *messageFrame =[[MessageFrame alloc] init];38messageFrame.message =message;3940[self.messages addObject:messageFrame];41}42

(3)自动滚动在最底端

1//滚动到最新的消息2NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count -1inSection:0];3[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

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