iPhone开发——通过代码自定义cell实现qq聊天界面

来源:互联网 发布:旺达与巨像结局 知乎 编辑:程序博客网 时间:2024/05/04 23:45

1.实现如下效果图


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