1.实现如下效果图
![iPhone开发——通过代码自定义cell实现qq聊天界面_第1张图片](http://img.e-com-net.com/image/info5/4ecad1475e794de4ae79645af5a83600.jpg)
2.具体实现
2.1plist文件
2.2搭建界面
2.3代码实现
2.3.1模型类
//
// MJMessage.m
#import "MJMessage.h"
@implementation MJMessage
+ (instancetype)messageWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
//
// MJMessage.h
#import <Foundation/Foundation.h>
typedef enum {
MJMessageTypeMe = 0, // 自己发的
MJMessageTypeOther // 别人发的
} MJMessageType;
@interface MJMessage : NSObject
/**
* 聊天内容
*/
@property (nonatomic, copy) NSString *text;
/**
* 发送时间
*/
@property (nonatomic, copy) NSString *time;
/**
* 信息的类型
*/
@property (nonatomic, assign) MJMessageType type;
+ (instancetype)messageWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
//
// MJMessageFrame.h
// 正文的字体
#define MJTextFont [UIFont systemFontOfSize:15]
#import <Foundation/Foundation.h>
@class MJMessage;
@interface MJMessageFrame : 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) MJMessage *message;
@end
//
// MJMessageFrame.m
#import "MJMessageFrame.h"
#import "MJMessage.h"
@implementation MJMessageFrame
/**
* 计算文字尺寸
*
* @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:(MJMessage *)message
{
_message = message;
// 间距
CGFloat padding = 10;
// 屏幕的宽度
CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
// 1.时间
CGFloat timeX = 0;
CGFloat timeY = 0;
CGFloat timeW = screenW;
CGFloat timeH = 40;
_timeF = CGRectMake(timeX, timeY, timeW, timeH); //因为timeF属性是readonly的所以没有自动生成set方法 所以不能用点语法 所以用_timeF
// 2.头像
CGFloat iconY = CGRectGetMaxY(_timeF); //头像的y值就是时间的最大Y值
CGFloat iconW = 40;
CGFloat iconH = 40;
CGFloat iconX;
if (message.type == MJMessageTypeOther) {// 别人发的
iconX = padding;
} else { // 自己的发的
iconX = screenW - padding - iconW;
}
_iconF = CGRectMake(iconX, iconY, iconW, iconH);
// 3.正文
CGFloat textY = iconY;
// 文字的尺寸
CGSize textMaxSize = CGSizeMake(150, MAXFLOAT); //文字不限高度 ,要限制宽度
CGSize textSize = [self sizeWithText:message.text font:MJTextFont maxSize:textMaxSize];
CGFloat textX;
if (message.type == MJMessageTypeOther) {// 别人发的
textX = CGRectGetMaxX(_iconF) + padding;
} else {// 自己的发的
textX = iconX - padding - textSize.width;
}
// _textF = CGRectMake(textX, textY, textSize.width, textSize.height);
_textF = (CGRect){{textX, textY}, textSize};
// 4.cell的高度
CGFloat textMaxY = CGRectGetMaxY(_textF);
CGFloat iconMaxY = CGRectGetMaxY(_iconF);
_cellHeight = MAX(textMaxY, iconMaxY) + padding; //正文和头像的最大Y值的较大者加上间距就是cell的高度
}
@end
2.3.2自定义cell
//
// MJMessageCell.h
//
#import <UIKit/UIKit.h>
@class MJMessageFrame;
@interface MJMessageCell : UITableViewCell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@property (nonatomic, strong) MJMessageFrame *messageFrame;
@end
//
// MJMessageCell.m
#import "MJMessageCell.h"
#import "MJMessageFrame.h"
#import "MJMessage.h"
@interface MJMessageCell()
/**
* 时间
*/
@property (nonatomic, weak) UILabel *timeView;
/**
* 头像
*/
@property (nonatomic, weak) UIImageView *iconView;
/**
* 正文
*/
@property (nonatomic, weak) UIButton *textView;
@end
@implementation MJMessageCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"message";
MJMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[MJMessageCell 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]; //因为这个属性定义的是弱指针类型的 所以这行代码过后就会被销毁 所以先用一个强指针指向刚创建的这个对象然后把它添加到contentView中
// timeView.backgroundColor = [UIColor redColor];
timeView.textAlignment = NSTextAlignmentCenter;
timeView.textColor = [UIColor grayColor];
timeView.font = [UIFont systemFontOfSize:13];
[self.contentView addSubview:timeView]; //把刚创建的那个lable对象添加到contentView中
self.timeView = timeView;
// 2.头像
UIImageView *iconView = [[UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView;
// 3.正文
UIButton *textView = [[UIButton alloc] init];
textView.titleLabel.numberOfLines = 0; // 自动换行
textView.backgroundColor = [UIColor purpleColor];
textView.titleLabel.font = MJTextFont;
[self.contentView addSubview:textView];
self.textView = textView;
// 4.设置cell的背景色
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)setMessageFrame:(MJMessageFrame *)messageFrame
{
_messageFrame = messageFrame;
MJMessage *message = messageFrame.message;
// 1.时间
self.timeView.text = message.time;
self.timeView.frame = messageFrame.timeF;
// 2.头像
NSString *icon = (message.type == MJMessageTypeMe) ? @"me" : @"other";
self.iconView.image = [UIImage imageNamed:icon];
self.iconView.frame = messageFrame.iconF;
// 3.正文
[self.textView setTitle:message.text forState:UIControlStateNormal];
self.textView.frame = messageFrame.textF;
}
@end
2.3.3控制器
//
// MJViewController.m
#import "MJViewController.h"
#import "MJMessage.h"
#import "MJMessageFrame.h"
#import "MJMessageCell.h"
@interface MJViewController () <UITableViewDataSource, UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *messageFrames;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 设置背景色和去除分割线
self.tableView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (NSMutableArray *)messageFrames
{
if (_messageFrames == nil) {
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]];
NSMutableArray *mfArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
// 消息模型
MJMessage *msg = [MJMessage messageWithDict:dict];
// frame模型
MJMessageFrame *mf = [[MJMessageFrame alloc] init];
mf.message = msg;
// 添加模型
[mfArray addObject:mf];
}
_messageFrames = mfArray;
}
return _messageFrames;
}
#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.messageFrames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
MJMessageCell *cell = [MJMessageCell cellWithTableView:tableView];
// 2.给cell传递模型
cell.messageFrame = self.messageFrames[indexPath.row];
// 3.返回cell
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
MJMessageFrame *mf = self.messageFrames[indexPath.row];
return mf.cellHeight;
}
@end