一、Model
BWMessage.h
#importtypedef 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 #import2 #import 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 @end18 19 20 #import "BWMessageFrame.h"21 #import 22 #import "BWMessage.h"23 #import "NSString+BWTextSize.h"24 25 @implementation BWMessageFrame26 27 //重写setMessage28 - (void)setMessage:(BWMessage *)message29 {30 _message = message;31 32 //计算每个控件的Frame33 34 //设置统一的间距35 CGFloat margin = 5;36 //获取屏幕的宽度37 CGFloat screenW = [UIScreen mainScreen].bounds.size.width;38 //计算时间label的frame39 CGFloat timeX = 0;40 CGFloat timeY = 0;41 CGFloat timeW = screenW;42 CGFloat timeH = 15;43 44 if (!message.hideTime) {45 //如果需要时间Label,那么再计算frame46 _timeFrame = CGRectMake(timeX, timeY, timeW, timeH);47 }48 49 //计算头像的frame50 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 //计算正文的frame57 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值+margin66 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 #import9 #import 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 @end19 20 // NSString+BWTextSize.m21 // 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 *)font33 {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 *)font39 {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 #import9 @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 //设置正文的内容和frame105 [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 code140 }141 142 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {143 [super setSelected:selected animated:animated];144 145 // Configure the view for the selected state146 }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 ()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 *)indexPath102 {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 *)indexPath114 {115 BWMessageFrame *frameModel = self.arrMessageFrame[indexPath.row];116 return frameModel.rowHeight;117 }118 119 #pragma mark - 懒加载120 - (NSMutableArray *)arrMessageFrame121 {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 else142 {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 *)noteInfo180 {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)dealloc201 {202 [[NSNotificationCenter defaultCenter] removeObserver:self];203 }204 205 - (BOOL)prefersStatusBarHidden206 {207 return YES;208 }209 210 - (void)didReceiveMemoryWarning {211 [super didReceiveMemoryWarning];212 // Dispose of any resources that can be recreated.213 }214 215 @end