简述整个项目的开发过程
1.在main.stroybord 中搭建基本界面
2.创建模型,一个是数据模型,一个是frame模型
3.实现对cell操作的封装
4.解决显示时间的细节问题
5.解决聊天内容的背景问题
6.用通知机制监听键盘
7.发送消息
一、在main.stroybord 中搭建基本界面
二、创建模型,一个是数据模型,一个是frame模型
根据message.plist文件创建模型
数据模型ZLMessage
1 #import2 3 4 5 typedef enum { 6 ZLMessageTypeMe = 0, //0表示自己,并且系统默认的 也是0 ,然后递增加1 7 ZLMessageTypeOther 8 }ZLMessageType; 9 10 @interface ZLMessage : NSObject11 12 //时间13 @property (nonatomic, strong) NSString *time;14 15 //内容16 @property (nonatomic, strong)NSString *text;17 18 //类型19 @property (nonatomic, assign)ZLMessageType type;20 21 //是否显示时间22 @property (nonatomic, assign)BOOL hideTime;23 24 +(instancetype)messageWithDict:(NSDictionary *)dict;25 -(instancetype)initWithDict:(NSDictionary *)dict;26 @end
#import "ZLMessage.h"@implementation ZLMessage+(instancetype)messageWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict];}-(instancetype)initWithDict:(NSDictionary *)dict{ if (self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self;}@end
frame模型ZLMessageFrame
#import#import "UIKit/UIkit.h"@class ZLMessage;@interface ZLMessageFrame : NSObject// 头像的frame@property (nonatomic, assign, readonly) CGRect iconF;//时间的frame@property (nonatomic, assign, readonly) CGRect timeF;//正文的frame@property (nonatomic, assign, readonly) CGRect textF;//cell的高度@property (nonatomic, assign, readonly) CGFloat cellHeight;//数据模型@property (nonatomic, strong) ZLMessage* message;@end
#define ZLTextFont [UIFont systemFontOfSize:15]
#import "ZLMessageFrame.h"
#import "ZLMessage.h"
@implementation ZLMessageFrame
/**
* 计算文字尺寸
*
* @param text 需要计算尺寸的文字
* @param font 文字的字体
* @param maxSize 文字的最大尺寸
*/
- (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize
{
NSDictionary *attrs = @{ NSFontAttributeName : font};
return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}
-(void)setMessage:(ZLMessage *)message
{ _message = message;
//计算头像,正文,时间的Frame
CGFloat sreenW = [UIScreen mainScreen].bounds.size.width;
CGFloat padding = 10;
//1.时间 CGFloat timeX = 0;
CGFloat timeY = 0;
CGFloat timeW = sreenW;
CGFloat timeH = 40;
_timeF = CGRectMake(timeX, timeY, timeW, timeH);
//2.头像
CGFloat iconY = CGRectGetMaxY(_timeF);
CGFloat iconW = 40;
CGFloat iconH = 40;
CGFloat iconX;
if (message.type == ZLMessageTypeOther) {
iconX = padding;
} else {
iconX = sreenW - iconW - padding;
}
_iconF = CGRectMake(iconX, iconY, iconW, iconH);
//3.正文
CGFloat textY = iconY;
CGFloat textX;
//文字的尺寸
CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);
CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize];
if (message.type == ZLMessageTypeOther) {
textX = CGRectGetMaxX(_iconF) + padding;
} else {
textX = iconX - padding - textSize.width;
}
_textF = (CGRect){ {textX,textY},textSize};
//cell 的高度
CGFloat textMaxY = CGRectGetMaxY(_textF);
CGFloat iconMaxY = CGRectGetMaxY(_iconF);
_cellHeight = MAX(textMaxY, iconMaxY) + padding;
}
@end
- (NSMutableArray *)messagesFrames{ if (_messagesFrames == nil){ //取出路径 NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]; //取出该路劲下的数组 NSArray *dictArray = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *mfArray = [NSMutableArray array]; //遍历数组形成字典 for (NSDictionary* dict in dictArray) { //消息模型 ZLMessage *msg = [ZLMessage messageWithDict:dict]; //frame模型 ZLMessageFrame *mgf =[[ZLMessageFrame alloc] init]; mgf.message = msg; [mfArray addObject:mgf]; } _messagesFrames = mfArray; } return _messagesFrames;}
三、实现对cell操作的封装
#import@class ZLMessageFrame;@interface ZLMessageCell : UITableViewCell+(instancetype) cellWithTableView:(UITableView *)tableView;@property (nonatomic, strong) ZLMessageFrame* messageFrame;@end
#define ZLTextFont [UIFont systemFontOfSize:15]#import "ZLMessageCell.h"#import "ZLMessageFrame.h"#import "ZLMessage.h"@interface ZLMessageCell()//时间@property (nonatomic, weak) UILabel *timeView;//头像@property (nonatomic, weak) UIImageView *iconView;//正文@property (nonatomic, weak) UIButton *textView;;@end@implementation ZLMessageCell+(instancetype) cellWithTableView:(UITableView *)tableView{ static NSString *ID = @"message"; //先从缓存池中取cell ZLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID ]; //如果缓存池中没有就自己创建cell,并且要带有标记 if (cell == nil) { cell = [[ZLMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell;}//做一次性的初始化-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self){ //子控件的创建和初始化 //1.时间 UILabel *timeView = [[UILabel alloc] init]; timeView.textColor = [UIColor grayColor]; timeView.textAlignment = NSTextAlignmentCenter; timeView.font = [UIFont systemFontOfSize:13]; [self.contentView addSubview:timeView]; self.timeView = timeView; //2.头像 UIImageView *iconView = [[UIImageView alloc] init]; //iconView.backgroundColor = [UIColor redColor]; [self.contentView addSubview:iconView]; self.iconView = iconView; //3.正文 UIButton *textView = [[UIButton alloc] init]; textView.titleLabel.numberOfLines = 0;//自动换行 textView.backgroundColor = [UIColor purpleColor]; textView.titleLabel.font = ZLTextFont; [self.contentView addSubview:textView]; self.textView = textView; } return self;}-(void)setMessageFrame:(ZLMessageFrame *)messageFrame{ _messageFrame = messageFrame; ZLMessage *message = messageFrame.message; //时间 self.timeView.text = message.time; self.timeView.frame = messageFrame.timeF; //头像 NSString *icon = (message.type == ZLMessageTypeMe) ? @"me" : @"other"; self.iconView.image = [UIImage imageNamed:icon]; self.iconView.frame = messageFrame.iconF; //正文 [self.textView setTitle:message.text forState:UIControlStateNormal]; self.textView.frame = messageFrame.textF;}@end
四、解决显示时间的细节问题
如果时间是一样的,就只显示一个时间
在ZLMessage.h文件中添加属性//是否显示时间@property (nonatomic, assign)BOOL hideTime;
在控制器.m文件中添加代码,即取出上一个模型和刚刚添加的模型的时间作比较,如果时间一样,就只显示上一个模型的time数据//遍历数组形成字典 for (NSDictionary* dict in dictArray) { //消息模型 ZLMessage *msg = [ZLMessage messageWithDict:dict]; //取出上一个模型 ZLMessageFrame *lastMf = [mfArray lastObject]; ZLMessage *lastMg = lastMf.message; msg.hideTime = [msg.time isEqualToString:lastMg.
五、解决聊天内容的背景问题
//设置图片if (message.type == MJMessageTypeMe) { // 自己发的,蓝色 [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal]; } else { // 别人发的,白色 [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal]; }
//为了显示对话框背景图,需要设置正文按钮的内边距 textView.contentEdgeInsets = UIEdgeInsetsMake(ZLTextPadding, ZLTextPadding, ZLTextPadding, ZLTextPadding);
//文字计算的最大尺寸 CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);//文字计算出来的真实尺寸(显示文字的尺寸) CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize]; //按钮最终的尺寸 CGSize textBtnSize = CGSizeMake(textSize.width +ZLTextPadding *2, textSize.height +ZLTextPadding *2); if (message.type == ZLMessageTypeOther) { textX = CGRectGetMaxX(_iconF) + padding; } else { textX = iconX - padding - textBtnSize.width; }// _textF = CGRectMake(textX, textY, textSize.width +40, textSize.height +40); _textF = (CGRect){ {textX,textY},textBtnSize};
六、用通知机制监听键盘
首先介绍一下通知机制
代码如下:
// 监听键盘的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];//取消监听- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self];}/** * 当键盘改变了frame(位置和尺寸)的时候调用 */- (void)keyboardWillChangeFrame:(NSNotification *)note{ // 设置窗口的颜色 self.view.window.backgroundColor = self.tableView.backgroundColor; // 0.取出键盘动画的时间 CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // 1.取得键盘最后的frame CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; // 2.计算控制器的view需要平移的距离 CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height; // 3.执行动画 [UIView animateWithDuration:duration animations:^{ self.view.transform = CGAffineTransformMakeTranslation(0, transformY); }];}
7.发送消息
//监听文本框#import "MJViewController.h"#import "MJMessage.h"#import "MJMessageFrame.h"#import "MJMessageCell.h"@interface MJViewController ()@property (weak, nonatomic) IBOutlet UITableView *tableView;@property (nonatomic, strong) NSMutableArray *messageFrames;@property (weak, nonatomic) IBOutlet UITextField *inputView;@property (nonatomic, strong) NSDictionary *autoreply;@end@implementation MJViewController- (void)viewDidLoad{ [super viewDidLoad]; // 1.表格的设置 // 去除分割线 self.tableView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0]; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.allowsSelection = NO; // 不允许选中 self.tableView.delegate = self; // 2.监听键盘的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; // 3.设置文本框左边显示的view self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)]; // 永远显示 self.inputView.leftViewMode = UITextFieldViewModeAlways; self.inputView.delegate = self;}/** * 发送一条消息 */- (void)addMessage:(NSString *)text type:(MJMessageType)type{ // 1.数据模型 MJMessage *msg = [[MJMessage alloc] init]; msg.type = type; msg.text = text; // 设置数据模型的时间 NSDate *now = [NSDate date]; NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = @"HH:mm"; // NSDate ---> NSString // NSString ---> NSDate // fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss"; // 2014-08-09 15:45:56 // 09/08/2014 15:45:56 msg.time = [fmt stringFromDate:now]; // 看是否需要隐藏时间 MJMessageFrame *lastMf = [self.messageFrames lastObject]; MJMessage *lastMsg = lastMf.message; msg.hideTime = [msg.time isEqualToString:lastMsg.time]; // 2.frame模型 MJMessageFrame *mf = [[MJMessageFrame alloc] init]; mf.message = msg; [self.messageFrames addObject:mf]; // 3.刷新表格 [self.tableView reloadData]; // 4.自动滚动表格到最后一行 NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0]; [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];}/** * 根据自己发的内容取得自动回复的内容 * * @param text 自己发的内容 */- (NSString *)replayWithText:(NSString *)text{ for (int i = 0; i
最终界面如图:
学的不精,笔记做的不好,见谅见谅。。。。。。。