先看一看效果吧!
废话不多说直接上代码
先看一看代码结构图:
MessageModel代码:
#import "MessageModel.h"
@implementation MessageModel
/**
* 类方法创建一个消息模型实例
*
* @param dic 描述模型的字典
*
* @return 消息模型实例
*/
+ (instancetype)messageModelWithDictionary:(NSDictionary *)dic
{
return [[self alloc] initWithDictionary:dic];
}
/**
* 自定义初始化方法
*
* @param dic 描述模型的字典
*
* @return 消息模型实例
*/
- (instancetype)initWithDictionary:(NSDictionary *)dic
{
if (self = [super init]) {
if (dic) {
[self setValuesForKeysWithDictionary:dic];
}
}
return self;
}
@end
MessageFrameModel代码:
#import "MessageFrameModel.h"
#import "MainDefine.h"
#import "NSString+Extension.h"
@implementation MessageFrameModel
- (void)setIsHideTime:(BOOL)isHideTime
{
_isHideTime = isHideTime;
//设置计算出来的frame数据
[self settingCalculationData];
}
/**
* 类方法创建一个带有对应控件frame的消息模型实例
*
* @param dic 描述模型的字典
*
* @return 消息模型实例
*/
+ (instancetype)messageFrameModelWithDescription:(NSDictionary *)dic
{
return [[self alloc] initWithDescription:dic];
}
/**
* 自定义初始化方法
*
* @param dic 描述模型的字典
*
* @return 消息模型实例
*/
- (instancetype)initWithDescription:(NSDictionary *)dic
{
if (self = [super initWithDictionary:dic]) {
if (dic) {
//设置计算出来的frame数据
//[self settingCalculationData:dic];
}
}
return self;
}
/**
* 根据基础数据计算对应控件的frame
*
* @param dic 基础数据字典
*/
- (void)settingCalculationData
{
CGFloat spacing = 8.0;
CGFloat timeX = 0.0;
CGFloat timeY = 0.0;
CGFloat timeHeight = 44.0;
CGFloat iconWith = 50.0;
if (!self.isHideTime) {
self.timeFrame = CGRectMake(timeX, timeY, MAINSCREEM_WITH, timeHeight);
}
if (self.type == MessageTypeMySend)
{
self.iconFrame = CGRectMake(MAINSCREEM_WITH - spacing - iconWith, CGRectGetMaxY(self.timeFrame) + 8, iconWith, iconWith);
}
else
{
self.iconFrame = CGRectMake(spacing, CGRectGetMaxY(self.timeFrame) + spacing, iconWith, iconWith);
}
CGFloat targetWidth = MAINSCREEM_WITH - spacing - self.iconFrame.size.width*2 - TEXTBUTTON_PADDING*2;
CGSize wordsS = [self.text autoSizeWithTargetWidth:targetWidth andFont:[UIFont systemFontOfSize:MEDIUM_FONT]];
CGFloat textX = spacing + self.iconFrame.size.width;
if (self.type == MessageTypeMySend) {
textX = MAINSCREEM_WITH - textX - wordsS.width - TEXTBUTTON_PADDING*2;
}
self.textFrame = CGRectMake(textX, self.iconFrame.origin.y, wordsS.width + TEXTBUTTON_PADDING*2, wordsS.height + TEXTBUTTON_PADDING*2);
self.cellHeight = MAX(CGRectGetMaxY(self.iconFrame), CGRectGetMaxY(self.textFrame));
}
MessageFrameModelList代码:
#import "MessageFrameModelList.h"
@interface MessageFrameModelList()
@property (strong, nonatomic)NSMutableArray *messageFrameModels;
@end
@implementation MessageFrameModelList
- (NSInteger)count
{
return self.messageFrameModels.count;
}
/**
* 类方法创建一个带有对应控件frame的消息模型列表实例
*
* @param dic 描述模型列表的数组
*
* @return 消息模型列表
*/
+ (instancetype)messageFrameModelListWithArray:(NSArray *)arr
{
return [[self alloc] initWithArray:arr];
}
/**
* 自定义初始化方法
*
* @param dic 描述模型列表的数组
*
* @return 消息模型列表
*/
- (instancetype)initWithArray:(NSArray *)arr
{
if (self = [super init])
{
if (arr)
{
self.messageFrameModels = [NSMutableArray arrayWithCapacity:1];
NSArray *messageArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages" ofType:@"plist"]];
for (int index = 0; index < messageArr.count; index++)
{
MessageFrameModel *messageFrameModel = [MessageFrameModel messageFrameModelWithDescription:messageArr[index]];
MessageFrameModel *lastMessageFrameModel = [self.messageFrameModels lastObject];
messageFrameModel.isHideTime = [messageFrameModel.time isEqual:lastMessageFrameModel.time];//如果和上一条消息时间相等,就隐藏时间
[self.messageFrameModels addObject:messageFrameModel];
}
}
}
return self;
}
/**
* 根据标号获取模型列表中的一个模型
*
* @param index 标号
*
* @return 带有对应控件frame的消息模型
*/
- (MessageFrameModel *)getMessageFrameModel:(NSInteger)index
{
return self.messageFrameModels[index];
}
/**
* 添加一条消息
*
* @param messageDic 消息描述字典
*/
- (void)addMessageWithDictionary:(NSDictionary *)messageDic
{
MessageFrameModel *messageFrameModel = [MessageFrameModel messageFrameModelWithDescription:messageDic];
//设置是否隐藏时间
MessageFrameModel *lastMessageFrameModel = [self.messageFrameModels lastObject];
messageFrameModel.isHideTime = [messageFrameModel.time isEqualToString:lastMessageFrameModel.time];
[self.messageFrameModels addObject:messageFrameModel];
}
@end
MessageCell代码:
#import "MessageCell.h"
#import "MainDefine.h"
@interface MessageCell()
/**
* 时间
*/
@property (strong, nonatomic)UILabel *timeLabel;
/**
* 头像
*/
@property (strong, nonatomic)UIImageView *iconImageView;
/**
* 内容
*/
@property (strong, nonatomic)UIButton *textButton;
@end
@implementation MessageCell
/**
* 类方法返回一个能重用的cell
*
* @param tableView 使用此cell的tableView
* @param identifier 此类cell的重用标识符
*
* @return 本cell的一个实例
*/
+ (instancetype)messageCell:(UITableView *)tableView
{
static NSString *cellIdentifier = @"messageCell";
MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
return cell;
}
/**
* 设置cell的内部控件大小
*
* @param messageFrameModel 带对应控件大小的消息模型
*/
- (void)setMessageFrameModel:(MessageFrameModel *)messageFrameModel
{
if (messageFrameModel) {
_messageFrameModel = messageFrameModel;
self.timeLabel.frame = messageFrameModel.timeFrame;
self.timeLabel.text = messageFrameModel.time;
self.timeLabel.hidden = messageFrameModel.isHideTime;
self.iconImageView.frame = messageFrameModel.iconFrame;
self.iconImageView.layer.cornerRadius = messageFrameModel.iconFrame.size.width/2;
self.iconImageView.layer.masksToBounds = YES;
self.iconImageView.image = [UIImage imageNamed:messageFrameModel.type == MessageTypeMySend ? @"me" : @"other"];
self.textButton.frame = messageFrameModel.textFrame;
[self.textButton setTitle:messageFrameModel.text forState:UIControlStateNormal];
if (self.messageFrameModel.type == MessageTypeMySend)
{
[self.textButton setBackgroundImage:[self imageWithName:@"chat_send_nor"] forState:UIControlStateNormal];
[self.textButton setBackgroundImage:[self imageWithName:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
}
else
{
[self.textButton setBackgroundImage:[self imageWithName:@"chat_recive_nor"] forState:UIControlStateNormal];
[self.textButton setBackgroundImage:[self imageWithName:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
}
}
}
/**
* 不变形的拉伸图片
*
* @param name 图片名称
*
* @return 拉伸后的图片
*/
- (UIImage *)imageWithName:(NSString *)name
{
UIImage *image = [UIImage imageNamed:name];
CGFloat imageW = image.size.width/2;
CGFloat imageH = image.size.height/2;
return [image resizableImageWithCapInsets:UIEdgeInsetsMake(imageH, imageW, imageH, imageW)];
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.timeLabel = [[UILabel alloc] init];
self.timeLabel.textAlignment = NSTextAlignmentCenter;
self.timeLabel.font = [UIFont systemFontOfSize:SMOLL_FONT];
self.timeLabel.textColor = [UIColor grayColor];
[self.contentView addSubview:self.timeLabel];
self.iconImageView = [[UIImageView alloc] init];
[self.contentView addSubview:self.iconImageView];
self.textButton = [[UIButton alloc] init];
[self.textButton setTitleEdgeInsets:UIEdgeInsetsMake(TEXTBUTTON_PADDING, TEXTBUTTON_PADDING, TEXTBUTTON_PADDING, TEXTBUTTON_PADDING)];
self.textButton.titleLabel.font = [UIFont systemFontOfSize:MEDIUM_FONT];
self.textButton.titleLabel.numberOfLines = 0;
[self.textButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.contentView addSubview:self.textButton];
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
ViewController代码:
#import "ViewController.h"
#import "MessageFrameModelList.h"
#import "MessageCell.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *textField;
/**
* 带frame的消息数据模型表
*/
@property (strong, nonatomic)MessageFrameModelList *messageFrameModelList;
@end
@implementation ViewController
#pragma mark - 属性方法
- (MessageFrameModelList *)messageFrameModelList
{
if (!_messageFrameModelList) {
NSArray *arr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages" ofType:@"plist"]];
_messageFrameModelList = [MessageFrameModelList messageFrameModelListWithArray:arr];
//消息最开始滚到最后
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messageFrameModelList.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
return _messageFrameModelList;
}
#pragma mark - 控制器周期
- (void)viewDidLoad {
[super viewDidLoad];
//注册键盘通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
//设置文本框左边距
self.textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 4, 0)];
self.textField.leftViewMode = UITextFieldViewModeAlways;
//设置文本框代理
self.textField.delegate = self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - 按钮手势事件
- (IBAction)didViewCtrClicked:(id)sender {
[self.view endEditing:YES];
}
- (IBAction)didAddClicked:(UIButton *)sender {
[self.view endEditing:YES];
}
#pragma 自定义方法
/*
UIKeyboardAnimationCurveUserInfoKey = 7; // 动画的执行节奏(速度)
UIKeyboardAnimationDurationUserInfoKey = "0.25"; // 键盘弹出\隐藏动画所需要的时间
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}";
UIKeyboardFrameChangedByUserInteraction = 0;
// 键盘弹出
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";// 键盘刚出来那一刻的frame
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; // 键盘显示完毕后的frame
// 键盘隐藏
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
*/
- (void)keyboardWillChangeFrame:(NSNotification *)notification
{
//NSLog(@"%@",notification.userInfo);
//self.view.frame = CGRectMake(self.view.frame.origin.x, [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y - self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
//self.view.transform = CGAffineTransformTranslate(self.view.transform, 0, [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y - [[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin.y);
//首尾式动画
[UIView beginAnimations:nil context:nil];
//设置动画时间
[UIView setAnimationDuration:[[notification.userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
//设置动画节奏
[UIView setAnimationCurve:[[notification.userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]];
self.view.transform = CGAffineTransformMakeTranslation(0, [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y - self.view.frame.size.height);
[UIView commitAnimations];
}
- (void)addMessage:(NSString *)messageStr andType:(MessageType)messageType
{
//设置时间
NSDate *nowDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSString *dateStr = [dateFormatter stringFromDate:nowDate];
NSDictionary *messageDic = @{@"text":messageStr,@"type":[NSNumber numberWithInteger:messageType],@"time":dateStr};
[self.messageFrameModelList addMessageWithDictionary:messageDic];
//刷新tableView
[self.tableView reloadData];
//tableView滚动到最新消息处
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messageFrameModelList.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
/**
* 根据自己发的内容取得自动回复的内容
*
* @param text 自己发的内容
*/
- (NSString *)autoReply:(NSString *)textStr
{
NSDictionary *repelyText = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"autoreply" ofType:@"plist"]];
for (NSInteger i = 0; i < textStr.length; i++) {
NSString *word = [textStr substringWithRange:NSMakeRange(i, 1)];
if (repelyText[word]) {
return repelyText[word];
}
}
return @"你妹啊";
}
#pragma mark - UITableView代理
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.messageFrameModelList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MessageCell *cell = [MessageCell messageCell:tableView];
cell.messageFrameModel = [self.messageFrameModelList getMessageFrameModel:indexPath.row];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [self.messageFrameModelList getMessageFrameModel:indexPath.row].cellHeight;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.view endEditing:YES];
}
#pragma mark - UITextField代理
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self addMessage:self.textField.text andType:MessageTypeMySend];
//清空输入框
self.textField.text = nil;
//模拟回复
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSString *autoReplyText = [self autoReply:[self.messageFrameModelList getMessageFrameModel:self.messageFrameModelList.count - 1].text];
[self addMessage:autoReplyText andType:MessageTypeOtherSend];
});
return YES;
}
@end