//
// ViewController.m
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import "ViewController.h"
#import "CZMessage.h"
#import "CZMessageCellFrame.h"
#import "CZMessageCell.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *inputText;
@property (nonatomic,strong) NSMutableArray *messageFrames;
@end
@implementation ViewController
//懒加载
- (NSMutableArray *) messageFrames
{
if (_messageFrames==nil) {
_messageFrames=[CZMessageCellFrame messageFrames];
}
return _messageFrames;
}
//隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.dataSource=self;
self.tableView.delegate=self;
self.inputText.delegate=self;
//去除表格的分割线
self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
//1.创建通知中心
NSNotificationCenter *center=[NSNotificationCenter defaultCenter];
//2.注册通知监听器
[center addObserver:self selector:@selector(keyboardFrameChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
//为tableView设置图片图片
UIImageView *bgView=[[UIImageView alloc] init];
bgView.image=[UIImage imageNamed:@"bgView"];
self.tableView.backgroundView=bgView;
}
//实现UITextFieldDelegate代理方法
//点击return 键的时候调用这个应方法
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
//1.获取文本框的内容
NSString *text=self.inputText.text;
//2.添加到模型数组中
CZMessageCellFrame *newFrame=[[CZMessageCellFrame alloc] init];
CZMessage *newMsg=[[CZMessage alloc] init];
newMsg.text=text;
NSDate *date=[NSDate date];
NSDateFormatter *format=[[NSDateFormatter alloc] init];
//一定要设置格式的的样式
format.dateFormat=@"HH:mm";
newMsg.time=[format stringFromDate:date];
//NSLog(@"%@",newMsg.time);
newMsg.type=MessageTypeMe;
CZMessageCellFrame *lastFrame=[self.messageFrames lastObject];
if (![lastFrame.message.time isEqualToString:newMsg.time]) {
newFrame.showTime=YES;
}
newFrame.message=newMsg;
[self.messageFrames addObject:newFrame];
//3.刷新tableView
[self.tableView reloadData];
NSIndexPath *path=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
//清空文本框的数据
self.inputText.text=nil;
return YES;
}
- (void) keyboardFrameChange:(NSNotification *)notice
{
NSDictionary *dic=notice.userInfo;
//NSLog(@"%@",dic);
CGFloat offset=[dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue].origin.y-self.view.frame.size.height;
//使整个view上移
self.view.transform=CGAffineTransformMakeTranslation(0, offset);
NSIndexPath *path=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.view endEditing:YES];
}
//确定所有行的数量
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.messageFrames.count;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.获取cell
CZMessageCell *cell=[CZMessageCell messageCell:tableView];
//清除单元格的背景色
cell.backgroundColor=[UIColor clearColor];
//2.为cell赋值
CZMessageCellFrame *frame=self.messageFrames[indexPath.row];
cell.messageFrame=frame;
//3.返回创建好的cell
return cell;
}
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CZMessageCellFrame *frame=self.messageFrames[indexPath.row];
return frame.cellHeight;
}
@end
<pre name="code" class="objc">//
// CZMessage.h
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
//消息类型
typedef enum
{
MessageTypeMe,
MessageTypeOther
}CZMessageType;
@interface CZMessage : NSObject
@property (nonatomic,copy) NSString *text;
@property (nonatomic,copy) NSString *time;
//类型--为了提高代码的可读性,将类型定义为枚举
@property (nonatomic,assign)CZMessageType type;
+ (NSArray *) messages;
+ (instancetype) messageWithDic:(NSDictionary *)dic;
- (instancetype) initWithDic:(NSDictionary *)dic;
@end
<pre name="code" class="objc">//
// CZMessage.m
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import "CZMessage.h"
@implementation CZMessage
+ (NSArray *) messages
{
NSArray *sourceArr=[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]];
NSMutableArray *desArr=[NSMutableArray array];
//循环遍历字典数组,字典转模型
for (NSDictionary *dic in sourceArr) {
//每一个字典对应着一个模型对象
CZMessage *msg=[CZMessage messageWithDic:dic];
[desArr addObject:msg];
}
return desArr;
}
+ (instancetype) messageWithDic:(NSDictionary *)dic
{
return [[self alloc] initWithDic:dic];
}
- (instancetype) initWithDic:(NSDictionary *)dic
{
if (self=[super init]) {
[self setValuesForKeysWithDictionary:dic];
}
return self;
}
@end
<pre name="code" class="objc">//
// CZMessageCellFrame.h
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#define btnPadding 20
@class CZMessage;
@interface CZMessageCellFrame : NSObject
//行高
@property (nonatomic,assign)CGFloat cellHeight;
//所有子控件的frame
@property (nonatomic,assign,readonly) CGRect timeViewF;
@property (nonatomic,assign,readonly) CGRect iconViewF;
@property (nonatomic,assign,readonly) CGRect textViewF;
//message数据模型
@property (nonatomic,strong) CZMessage *message;
//所以frame模型数据数组
+(NSMutableArray *)messageFrames;
//添加属性,标记是否需要显示时间 默认值:NO
@property (nonatomic,assign) BOOL showTime;
@end
<pre name="code" class="objc">//
// CZMessageCellFrame.m
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import "CZMessageCellFrame.h"
#import "CZMessage.h"
@implementation CZMessageCellFrame
//返回所有模型数据
+(NSMutableArray *)messageFrames
{
NSMutableArray *desArr=[NSMutableArray array];
//1.取出原始的message数据
NSArray *sourceArr=[CZMessage messages];
//循环遍历,将原始的message模型数据一个一个添加到Frame模型中
for (CZMessage *msg in sourceArr) {
CZMessageCellFrame *frame=[[CZMessageCellFrame alloc] init];
//判断是否需要显示时间
//1.得先取出desArr 中最后一个Frame模型
CZMessageCellFrame *lastFrame=[desArr lastObject];
//2.判断获取 的最后一个frame模型数据中message成员的time值是否与当前需要添加的msg时间相等
if(![lastFrame.message.time isEqualToString:msg.time])
{
frame.showTime=YES;
}
//赋值模型数据 1.提供创建cell所需要的message模型 2.计算子控件的frame和行高
frame.message=msg;
[desArr addObject:frame];
}
return desArr;
}
//计算子控件的frame和计算行高
- (void)setMessage:(CZMessage *)message
{
_message=message;
CGFloat padding=10;
//获取当前物理屏幕
UIScreen *screen=[UIScreen mainScreen];
//获取屏幕的宽度
CGFloat width=screen.bounds.size.width;
//1.计算时间的frame
CGFloat timeViewX=0;
CGFloat timeViewY=0;
CGFloat timeViewW=width;
CGFloat timeViewH=20;
_timeViewF=CGRectMake(timeViewX, timeViewY, timeViewW, timeViewH);
//2.计算头像的frame,判断消息类型
CGFloat iconViewW=30;
CGFloat iconViewH=iconViewW;
CGFloat iconViewX=0;
CGFloat iconViewY=CGRectGetMaxY(_timeViewF)+padding;
if (self.message.type==MessageTypeMe) {
iconViewX=width-padding-iconViewW;
}
else
{
iconViewX=padding;
}
_iconViewF=CGRectMake(iconViewX, iconViewY, iconViewW, iconViewH);
//3.计算textView的frame,主要计算文本占据的宽高
CGFloat textViewX=0;
CGFloat textViewY=CGRectGetMinY(_iconViewF)+padding;
//设置最大宽高,如果大于这个宽度则自动换行,如果小于这个宽度,则返回实际的宽
CGSize maxSize=CGSizeMake(250, MAXFLOAT);
//设置用来计算文本宽高的字体大小
NSDictionary *att=@{NSFontAttributeName:[UIFont systemFontOfSize:14]};
//计算文本的实际宽高
CGSize textSize=[self.message.text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:att context:nil].size;
CGFloat textViewW=textSize.width;
CGFloat textViewH=textSize.height;
//判断消息类型
if (self.message.type==MessageTypeMe) {
textViewX=iconViewX-padding-textViewW-2*btnPadding;
}
else
{
textViewX=CGRectGetMaxX(_iconViewF)+padding;
}
_textViewF=CGRectMake(textViewX, textViewY, textViewW+btnPadding*2, textViewH+btnPadding*2);
//4.计算行高
_cellHeight=CGRectGetMaxY(_textViewF)+padding;
}
@end
<pre name="code" class="objc">//
// CZMessageCell.h
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import <UIKit/UIKit.h>
@class CZMessageCellFrame;
@interface CZMessageCell : UITableViewCell
+ (instancetype) messageCell:(UITableView *)tableView;
@property (nonatomic,strong) CZMessageCellFrame *messageFrame;
@end
<pre name="code" class="objc">//
// CZMessageCell.m
// 01_QQ聊天信息
//
// Created by Itcast.GuangZhou on 15/9/23.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import "CZMessageCell.h"
#import "CZMessage.h"
#import "CZMessageCellFrame.h"
@interface CZMessageCell ()
@property (nonatomic,weak) UILabel *timeView;
@property (nonatomic,weak) UIImageView *iconView;
@property (nonatomic,weak) UIButton *textView;
@end
@implementation CZMessageCell
+ (instancetype) messageCell:(UITableView *)tableView
{
NSString *ID=@"QQ";
CZMessageCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
//这个方法是父类的方法,也就意味着它只能创建出父类中默认的系统自带的cell.而不能满足我们的需要,所以我们就需要做重写,在调用方法的时候调用我们子类自己重写过后的方法。
cell=[[CZMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
return cell;
}
//根据多态,系统会根据类型调用子类重写过后的方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
//1.先初始化父类成员
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//1.添加timeView
UILabel *timeView=[[UILabel alloc] init];
self.timeView=timeView;
//设置居中
timeView.textAlignment=NSTextAlignmentCenter;
timeView.font=[UIFont systemFontOfSize:13];
timeView.textColor=[UIColor lightGrayColor];
[self addSubview:timeView];
//2.添加iconView
UIImageView *iconView=[[UIImageView alloc] init];
self.iconView=iconView;
[self addSubview:iconView];
//3.添加textView
UIButton *textView=[[UIButton alloc] init];
self.textView=textView;
//设置按钮的文本色
[textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//设置按钮的字体大小
textView.titleLabel.font=[UIFont systemFontOfSize:14];
//设置自动换行
textView.titleLabel.numberOfLines=0;
//为按钮添加内容的内间距
textView.contentEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 20);
//为按钮添加背景色
//textView.backgroundColor=[UIColor redColor];
[self addSubview:textView];
}
return self;
}
- (void)setMessageFrame:(CZMessageCellFrame *)messageFrame
{
_messageFrame=messageFrame;
//设置数据
[self setDatas];
//设置frame
//[self setFrames];
}
//设置数据
- (void) setDatas
{
CZMessage *msg=self.messageFrame.message;
self.timeView.text=msg.time;
if (msg.type==MessageTypeMe) {
self.iconView.image=[UIImage imageNamed:@"me"];
//根据消息类型设置消息文本的背景图片
// [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_send_nor"] forState:UIControlStateNormal];
// [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
[self.textView setBackgroundImage:[self resizeImageWithName:@"chat_send_nor"] forState:UIControlStateNormal];
[self.textView setBackgroundImage:[self resizeImageWithName:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
}
else
{
self.iconView.image=[UIImage imageNamed:@"other"];
// [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_recive_nor"] forState:UIControlStateNormal];
// [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
[self.textView setBackgroundImage:[self resizeImageWithName:@"chat_recive_nor"] forState:UIControlStateNormal];
[self.textView setBackgroundImage:[self resizeImageWithName:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
}
[self.textView setTitle:msg.text forState:UIControlStateNormal];
}
//返回拉伸之后的图片
- (UIImage *) resizeImageWithName:(NSString *)name
{
return [[UIImage imageNamed:name] resizableImageWithCapInsets:UIEdgeInsetsMake(30, 20, 18, 30) resizingMode:UIImageResizingModeStretch];
}
//当将当前控件添加到父容器的时候,自动调用这个方法,设置它的子控件的Frame
//如现在这个情况:当创建好cell,添加到tableView中的时候,会调用这个方法设置cell 的三个子控件的frame
- (void) layoutSubviews
{
//判断是否需要显示时间
self.timeView.hidden=! self.messageFrame.showTime;
self.timeView.frame=self.messageFrame.timeViewF;
self.iconView.frame=self.messageFrame.iconViewF;
self.textView.frame=self.messageFrame.textViewF;
}
@end