一、Model
BWMessage.h
#import <Foundation/Foundation.h> typedef enum{ BWMessageMe = 0,//表示自己 BWMessageOther = 1 //表示对方 }BWMessageType; @interface BWMessage : NSObject //消息正文 @property(nonatomic, copy) NSString *text; //消息时间 @property(nonatomic, copy) NSString *time; //消息类型 @property(nonatomic, assign) BWMessageType type; //记录是否隐藏时间 @property(nonatomic, assign) BOOL hideTime; - (instancetype)initWithDict:(NSDictionary *)dict; + (instancetype)messageWithDict:(NSDictionary *)dict; @end #import "BWMessage.h" @implementation BWMessage - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { // _text = dict[@"text"]; // _time = dict[@"time"]; // _type =(BWMessageType)dict[@"type"]; [self setValuesForKeysWithDictionary:dict]; } return self; } + (instancetype)messageWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } @end
BWMessageFrame.h
1 #import <Foundation/Foundation.h> 2 #import <CoreGraphics/CoreGraphics.h> 3 4 #define textFont [UIFont systemFontOfSize:16] 5 6 @class BWMessage; 7 8 @interface BWMessageFrame : NSObject 9 10 @property (nonatomic, strong) BWMessage *message; 11 @property (nonatomic, assign, readonly) CGRect timeFrame; 12 @property (nonatomic, assign, readonly) CGRect iconFrame; 13 @property (nonatomic, assign, readonly) CGRect textFrame; 14 15 @property (nonatomic, assign, readonly) CGFloat rowHeight; 16 17 @end 18 19 20 #import "BWMessageFrame.h" 21 #import <UIKit/UIKit.h> 22 #import "BWMessage.h" 23 #import "NSString+BWTextSize.h" 24 25 @implementation BWMessageFrame 26 27 //重写setMessage 28 - (void)setMessage:(BWMessage *)message 29 { 30 _message = message; 31 32 //计算每个控件的Frame 33 34 //设置统一的间距 35 CGFloat margin = 5; 36 //获取屏幕的宽度 37 CGFloat screenW = [UIScreen mainScreen].bounds.size.width; 38 //计算时间label的frame 39 CGFloat timeX = 0; 40 CGFloat timeY = 0; 41 CGFloat timeW = screenW; 42 CGFloat timeH = 15; 43 44 if (!message.hideTime) { 45 //如果需要时间Label,那么再计算frame 46 _timeFrame = CGRectMake(timeX, timeY, timeW, timeH); 47 } 48 49 //计算头像的frame 50 CGFloat iconW = 30; 51 CGFloat iconH = 30; 52 CGFloat iconY = CGRectGetMaxY(_timeFrame); 53 CGFloat iconX = message.type == BWMessageOther ? margin : screenW - iconW - margin; 54 _iconFrame = CGRectMake(iconX, iconY, iconW, iconH); 55 56 //计算正文的frame 57 CGSize textSize = [message.text sizeOfTextWithMaxsize:CGSizeMake(250, MAXFLOAT) andFont:textFont]; 58 CGFloat textW = textSize.width+40; 59 CGFloat textH = textSize.height+30; 60 CGFloat textY = iconY; 61 CGFloat textX = message.type == BWMessageOther ? CGRectGetMaxX(_iconFrame) : screenW - margin - iconW - textW; 62 _textFrame = CGRectMake(textX, textY, textW, textH); 63 64 //计算行高 65 //获取 头像的最大Y值和正文的最大Y值,然后用最大Y值+margin 66 CGFloat maxY = MAX(CGRectGetMaxY(_iconFrame), CGRectGetMaxY(_textFrame)); 67 _rowHeight = maxY + margin; 68 69 70 } 71 72 @end
NSString+BWTextSize.h
1 // NSString+BWTextSize.h 2 // IOS_QQ聊天 3 // 4 // Created by ma c on 16/1/10. 5 // Copyright (c) 2016年 博文科技. All rights reserved. 6 // 7 8 #import <Foundation/Foundation.h> 9 #import <UIKit/UIKit.h> 10 @interface NSString (BWTextSize) 11 12 //对象方法-计算文本尺寸 13 - (CGSize)sizeOfTextWithMaxsize:(CGSize)maxSize andFont:(UIFont *)font; 14 15 //类方法-计算文本尺寸 16 + (CGSize)sizeWithText:(NSString *)text andMaxSize:(CGSize)maxSize andFont:(UIFont *)font; 17 18 @end 19 20 // NSString+BWTextSize.m 21 // IOS_QQ聊天 22 // 23 // Created by ma c on 16/1/10. 24 // Copyright (c) 2016年 博文科技. All rights reserved. 25 // 26 27 #import "NSString+BWTextSize.h" 28 29 @implementation NSString (BWTextSize) 30 31 32 - (CGSize)sizeOfTextWithMaxsize:(CGSize)maxSize andFont:(UIFont *)font 33 { 34 NSDictionary *attr = @{NSFontAttributeName : font}; 35 return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil].size; 36 } 37 38 + (CGSize)sizeWithText:(NSString *)text andMaxSize:(CGSize)maxSize andFont:(UIFont *)font 39 { 40 return [text sizeOfTextWithMaxsize:maxSize andFont:font]; 41 } 42 43 @end
三、View
1 // BWMessageCell.h 2 // IOS_QQ聊天 3 // 4 // Created by ma c on 16/1/10. 5 // Copyright (c) 2016年 博文科技. All rights reserved. 6 // 7 8 #import <UIKit/UIKit.h> 9 @class BWMessageFrame; 10 11 @interface BWMessageCell : UITableViewCell 12 13 @property (nonatomic, strong) BWMessageFrame *messageFrame; 14 15 + (instancetype) messageCellWithTableView:(UITableView *)tableView; 16 17 @end 18 19 // BWMessageCell.m 20 // IOS_QQ聊天 21 // 22 // Created by ma c on 16/1/10. 23 // Copyright (c) 2016年 博文科技. All rights reserved. 24 // 25 26 #import "BWMessageCell.h" 27 #import "BWMessage.h" 28 #import "BWMessageFrame.h" 29 30 @interface BWMessageCell () 31 32 @property (nonatomic, strong) UILabel *lblTime; 33 @property (nonatomic, strong) UIImageView *imgViewHead; 34 @property (nonatomic, strong) UIButton *btnText; 35 36 @end 37 38 @implementation BWMessageCell 39 40 //创建自定义Cell 41 + (instancetype)messageCellWithTableView:(UITableView *)tableView 42 { 43 NSString *cellIdentifier = @"cellIdentifier"; 44 BWMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 45 if (!cell) { 46 cell = [[BWMessageCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier]; 47 } 48 //设置单元格的背景颜色 49 cell.backgroundColor = [UIColor clearColor]; 50 return cell; 51 } 52 53 #pragma mark - 重写initWithStyle的方法 54 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 55 { 56 if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 57 //创建子控件 58 59 //显示时间的label 60 self.lblTime = [[UILabel alloc] init]; 61 self.lblTime.textAlignment = NSTextAlignmentCenter; 62 self.lblTime.font = [UIFont systemFontOfSize:14]; 63 [self.contentView addSubview:self.lblTime]; 64 65 //显示头像的UIImageView 66 self.imgViewHead = [[UIImageView alloc] init]; 67 [self.contentView addSubview:self.imgViewHead]; 68 69 //显示正文的按钮 70 self.btnText = [[UIButton alloc] init]; 71 self.btnText.titleLabel.font = textFont; 72 [self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 73 self.btnText.titleLabel.numberOfLines = 0; 74 //self.btnText.backgroundColor = [UIColor purpleColor]; 75 //self.btnText.titleLabel.backgroundColor = [UIColor redColor]; 76 77 //设置按钮的内边距 78 self.btnText.contentEdgeInsets = UIEdgeInsetsMake(15, 20, 15, 20); 79 [self.contentView addSubview:self.btnText]; 80 } 81 return self; 82 } 83 #pragma mark - 重写setMessageFrame的方法 84 - (void)setMessageFrame:(BWMessageFrame *)messageFrame 85 { 86 _messageFrame = messageFrame; 87 88 //获取数据模型 89 BWMessage *message = messageFrame.message; 90 91 //分别设置控件的数据和frame 92 93 //设置时间的内容和frame 94 self.lblTime.text = message.time; 95 self.lblTime.frame = messageFrame.timeFrame; 96 self.lblTime.hidden = message.hideTime; 97 98 //设置头像的图片和frame 99 //根据消息类型,判断应该使用哪张图片 100 NSString *iconImg = message.type == BWMessageMe ? @"me" : @"other"; 101 self.imgViewHead.image = [UIImage imageNamed:iconImg]; 102 self.imgViewHead.frame = messageFrame.iconFrame; 103 104 //设置正文的内容和frame 105 [self.btnText setTitle:message.text forState:UIControlStateNormal]; 106 self.btnText.frame = messageFrame.textFrame; 107 108 //设置正文的背景图 109 NSString *imgNor,*imgHighlighted; 110 if (message.type == BWMessageMe) { 111 //自己发送的消息 112 imgNor = @"chat_send_nor"; 113 imgHighlighted = @"chat_send_press_pic"; 114 //设置消息字体的颜色 115 [self.btnText setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 116 } 117 else{ 118 //对方发送的消息 119 imgNor = @"chat_recive_nor"; 120 imgHighlighted = @"chat_recive_press_pic"; 121 //设置消息的字体颜色 122 [self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 123 } 124 //加载图片 125 UIImage *imageNor = [UIImage imageNamed:imgNor]; 126 UIImage *imageHighlighted = [UIImage imageNamed:imgHighlighted]; 127 128 //用平铺的方式拉伸图片 129 imageNor = [imageNor stretchableImageWithLeftCapWidth:imageNor.size.width/2 topCapHeight:imageNor.size.height/2]; 130 imageHighlighted = [imageHighlighted stretchableImageWithLeftCapWidth:imageHighlighted.size.width/2 topCapHeight:imageHighlighted.size.height/2]; 131 132 //设置背景图 133 [self.btnText setBackgroundImage:imageNor forState:UIControlStateNormal]; 134 [self.btnText setBackgroundImage:imageHighlighted forState:UIControlStateHighlighted]; 135 136 } 137 138 - (void)awakeFromNib { 139 // Initialization code 140 } 141 142 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 143 [super setSelected:selected animated:animated]; 144 145 // Configure the view for the selected state 146 } 147 148 @end
三、Controller
1 // ViewController.m 2 // IOS_QQ聊天 3 // 4 // Created by ma c on 16/1/9. 5 // Copyright (c) 2016年 博文科技. All rights reserved. 6 // 7 8 #import "ViewController.h" 9 #import "BWMessage.h" 10 #import "BWMessageFrame.h" 11 #import "BWMessageCell.h" 12 13 @interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate> 14 //消息的Frame模型对象 15 @property (nonatomic, strong) NSMutableArray *arrMessageFrame; 16 17 @property (weak, nonatomic) IBOutlet UITableView *tableView; 18 @property (weak, nonatomic) IBOutlet UITextField *textInput; 19 20 @end 21 22 @implementation ViewController 23 24 #pragma mark - 文本框代理方法 25 26 //return键被单击的时候触发 27 - (BOOL)textFieldShouldReturn:(UITextField *)textField 28 { 29 //1.获取用户输入的文本 30 NSString *text = textField.text; 31 32 //2.发送用户的消息 33 [self sendMessage:text withType:BWMessageMe]; 34 35 //3.发送系统的消息 36 [self sendMessage:@"不认识" withType:BWMessageOther]; 37 38 //4.清空文本框 39 textField.text = nil; 40 41 return YES; 42 } 43 //发送消息 44 - (void)sendMessage:(NSString *)msg withType:(BWMessageType)type 45 { 46 //1.创建一个数据模型和frame模型 47 //数据模型 48 BWMessage *model = [[BWMessage alloc] init]; 49 //获取当前系统时间 50 NSDate *nowDate = [NSDate date]; 51 //创建一个日期格式化器 52 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 53 //设置格式 54 formatter.dateFormat = @"今天:HH:mm"; 55 //进行日期的格式化 56 model.time = [formatter stringFromDate:nowDate]; 57 model.type = type; 58 model.text = msg; 59 60 //frame模型 61 BWMessageFrame *frameModel = [[BWMessageFrame alloc] init]; 62 frameModel.message = model; 63 //根据当前的消息时间和上一条消息的时间,来设置是否隐藏时间Label 64 BWMessageFrame *lastMessageFrame = [self.arrMessageFrame lastObject]; 65 NSString *lastTime = lastMessageFrame.message.time; 66 if ([model.time isEqualToString:lastTime]) { 67 model.hideTime = YES; 68 } 69 70 //2.把frame模型加载到集合中 71 [self.arrMessageFrame addObject:frameModel]; 72 73 //3.刷新UITableView数据 74 [self.tableView reloadData]; 75 76 //4.把最后一行滚动到最上面 77 NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.arrMessageFrame.count - 1 inSection:0]; 78 [self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; 79 } 80 81 82 #pragma mark - 滚动视图代理方法 83 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 84 { 85 //[self.textInput resignFirstResponder]; 86 //滚动把键盘叫回去 87 [self.view endEditing:YES]; 88 } 89 90 #pragma mark - 数据源方法 91 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 92 { 93 return 1; 94 } 95 96 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 97 { 98 return self.arrMessageFrame.count; 99 } 100 101 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 102 { 103 //1.获取模型数据 104 BWMessageFrame *frameModel = self.arrMessageFrame[indexPath.row]; 105 //2.创建单元格 106 BWMessageCell *cell = [BWMessageCell messageCellWithTableView:tableView]; 107 //3.把模型赋值给单元格 108 cell.messageFrame = frameModel; 109 //4.返回单元格 110 return cell; 111 } 112 113 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 114 { 115 BWMessageFrame *frameModel = self.arrMessageFrame[indexPath.row]; 116 return frameModel.rowHeight; 117 } 118 119 #pragma mark - 懒加载 120 - (NSMutableArray *)arrMessageFrame 121 { 122 if (_arrMessageFrame == nil) { 123 124 NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]; 125 126 NSArray *arrDict = [NSArray arrayWithContentsOfFile:path]; 127 NSMutableArray *arrModel = [NSMutableArray array]; 128 129 for (NSDictionary *dict in arrDict) { 130 //创建一个数据模型 131 BWMessage *dataModel = [BWMessage messageWithDict:dict]; 132 //创建一个Frame模型 133 BWMessageFrame *modelFrame = [[BWMessageFrame alloc] init]; 134 135 //获取上一个数据模型 136 BWMessage *lastMessage = (BWMessage *)[[arrModel lastObject] message]; 137 //判断“当前的模型时间”是否和“上一个模型时间”一样 138 if ([dataModel.time isEqualToString:lastMessage.time]) { 139 dataModel.hideTime = YES; 140 } 141 else 142 { 143 dataModel.hideTime = NO; 144 } 145 146 modelFrame.message = dataModel; 147 148 //把Frame模型加载到arrModel模型数组中 149 [arrModel addObject:modelFrame]; 150 } 151 _arrMessageFrame = arrModel; 152 } 153 return _arrMessageFrame; 154 } 155 156 #pragma mark - 视图加载 157 - (void)viewDidLoad { 158 [super viewDidLoad]; 159 //取消分割线 160 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 161 //设置TableView的背景色 162 self.tableView.backgroundColor = [UIColor colorWithRed:236.0/255 green:236.0/255 blue:236.0/255 alpha:1]; 163 //设置TableView的行不允许被选中 164 self.tableView.allowsSelection = NO; 165 //设置文本框距离最左侧有一段距离 166 UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 1)]; 167 //把leftView设置给文本框 168 self.textInput.leftView = leftView; 169 self.textInput.leftViewMode = UITextFieldViewModeWhileEditing; 170 171 //监听键盘的弹出事件 172 //1.创建一个NSNotificationCenter对象 173 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; 174 //2.监听键盘弹出发出的通知 175 [center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; 176 177 } 178 //通知关联方法 179 - (void)keyboardWillChangeFrame:(NSNotification *)noteInfo 180 { 181 // NSLog(@"通知的名称:%@",noteInfo.name); 182 // NSLog(@"通知的发布者:%@",noteInfo.object); 183 // NSLog(@"通知的内容:%@",noteInfo.userInfo); 184 //1.获取键盘显示完毕或者隐藏完毕后的Y值 185 CGRect rectEnd = [noteInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; 186 CGFloat keyboardY = rectEnd.origin.y; 187 //用键盘的Y值减去屏幕的高度计算平移的值 188 CGFloat transformValue = keyboardY - self.view.frame.size.height; 189 190 [UIView animateWithDuration:0.25 animations:^{ 191 192 self.view.transform = CGAffineTransformMakeTranslation(0, transformValue); 193 }]; 194 195 //让UITableView的最后一行滚动到最上面 196 NSIndexPath *lastRowindexPath = [NSIndexPath indexPathForRow:self.arrMessageFrame.count - 1 inSection:0]; 197 [self.tableView scrollToRowAtIndexPath:lastRowindexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; 198 } 199 200 - (void)dealloc 201 { 202 [[NSNotificationCenter defaultCenter] removeObserver:self]; 203 } 204 205 - (BOOL)prefersStatusBarHidden 206 { 207 return YES; 208 } 209 210 - (void)didReceiveMemoryWarning { 211 [super didReceiveMemoryWarning]; 212 // Dispose of any resources that can be recreated. 213 } 214 215 @end