ios-day07-02(模仿新浪微博:UITableView中cell的高度不一致,使用代码来自定义cell、UITableViewController的使用)

首先附上Demo的源码下载地址:http://download.csdn.net/detail/liu537192/8468169


ios-day07-01中我们使用的是xib来自定义cell,使用xib自定义cell适用于cell中的子控件个数一样且高度一致,如果cell中的子控件个数不一样且高度不一致时,我们就需要使用代码来自定义cell。

通过代码自定义cell(cell高度不一致)的步骤:

1,新建一个类继承自UITableViewCell


2,重写UITableViewCell的initWithStyle:reuseIdentifier:方法

2.1,添加所有需要显示的子控件,不需要设置子控件的数据和frame,子控件要添加到contentView中

2.2,进行子控件不变属性的赋值(有些属性只需要设置一次,比如字体、固定的图片等)


3,提供2个模型

3.1,数据模型:存放文字数据、图片数据

3.2,frame模型:存放3.1的数据模型、所有子控件的frame、cell的高度


4,自定义的cell中拥有一个frame模型(不要直接拥有数据模型,因为frame模型中包含了数据模型)


5,重写frame模型属性的setter方法:在这个方法中设置子控件的显示数据和子控件的frame


6,frame模型数据的初始化采用懒加载的方式(每一个cell对应的frame模型数据只会加载一次)


因为整个界面只有一个UITableView,所以我们可以使用UITableViewController。步骤如下:

1,让LiuJieViewController继承自UITableViewController,如下图所示


2,来到main.storyboard文件,删掉原来的控制器,弄一个UITableViewController,并设置其class为LiuJieViewController,如下图所示


3,这时,这个控制器的对应的view是一个UITableView,右键点击这个UITableView,发现UITableView的数据源和代理都已经自动设置好了,如下图所示



接下来,我们直接来看整个Demo的效果图:




核心代码:

//
//  LiuJieViewController.m
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "LiuJieViewController.h"
#import "LiuJieStatus.h"
#import "LiuJieStatusFrame.h"
#import "LiuJieStatusCell.h"

@interface LiuJieViewController ()

@property (nonatomic, strong) NSArray *statusFrames;
@end

@implementation LiuJieViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
//    self.tableView.rowHeight = 60;
}

- (BOOL)prefersStatusBarHidden{

    return YES;
}

- (NSArray *)statusFrames{

    if (_statusFrames == nil) {
        // 获取plist文件的路径
        NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
        // 加载plist文件中的数据到数组
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
        
        NSMutableArray *tempArray = [NSMutableArray array];
        // 字典对象转模型对象
        for (NSDictionary *dict in dictArray) {
            
            LiuJieStatus *status = [LiuJieStatus statusWithDict:dict];
            
            LiuJieStatusFrame *statusFrame = [[LiuJieStatusFrame alloc] init];
            statusFrame.status = status;
            
            [tempArray addObject:statusFrame];
        }
        
        _statusFrames = tempArray;
    }

    return _statusFrames;
}

#pragma mark -数据源的方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return self.statusFrames.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

//    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
    
    // 1,创建cell
    LiuJieStatusCell *cell = [LiuJieStatusCell cellWithTableView:tableView];
    
    // 2,给cell设置数据
    cell.statusFrame = self.statusFrames[indexPath.row];
    
    return cell;
}

#pragma mark -代理的方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    // 取出这行对应的frame模型
    LiuJieStatusFrame *statusFrame = self.statusFrames[indexPath.row];
    
    return statusFrame.cellHeight;
}

@end
//
//  LiuJieStatus.h
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

@interface LiuJieStatus : NSObject

@property (nonatomic,copy) NSString *icon;// 头像

@property (nonatomic,copy) NSString *name;// 昵称

@property (nonatomic,copy) NSString *text;// 内容

@property (nonatomic,copy) NSString *picture;// 配图

@property (nonatomic,assign) BOOL vip;// 是否是vip会员

+ (instancetype)statusWithDict:(NSDictionary *)dict;

- (instancetype)initWithDict:(NSDictionary *)dict;

@end
//
//  LiuJieStatus.m
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "LiuJieStatus.h"

@implementation LiuJieStatus

- (instancetype)initWithDict:(NSDictionary *)dict{

    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    
    return self;
}


+ (instancetype)statusWithDict:(NSDictionary *)dict{

    return [[self alloc] initWithDict:dict];
}

@end
//
//  LiuJieStatusFrame.h
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
     
     
      
      
@class LiuJieStatus;

@interface LiuJieStatusFrame : NSObject
/**
 *  头像的frame
 *  这里为什么要用readOnly呢?因为各个子控件的frame是根据一定的规则计算出来的,
 *  不能让别人随意的修改,使用readOnly的属性将只有get方法而没有set方法
 */
@property (nonatomic, assign, readonly) CGRect iconF;
/**
 *  昵称的frame
 */
@property (nonatomic, assign, readonly) CGRect nameF;
/**
 *  vip会员图标的frame
 */
@property (nonatomic, assign, readonly) CGRect vipF;
/**
 *  正文的frame
 */
@property (nonatomic, assign, readonly) CGRect textF;
/**
 *  配图的frame
 */
@property (nonatomic, assign, readonly) CGRect pictureF;
/**
 *  cell的高度
 */
@property (nonatomic, assign, readonly) CGFloat cellHeight;

/**
 *  各个子控件的frame需要根据LiuJieStatus来设置
 */
@property (nonatomic, strong) LiuJieStatus *status;

@end
//
//  LiuJieStatusFrame.m
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

// 昵称的字体
#define LiuJieNameFont [UIFont systemFontOfSize:14]
// 正文的字体
#define LiuJieTextFont [UIFont systemFontOfSize:15]

#import "LiuJieStatusFrame.h"
#import "LiuJieStatus.h"

@implementation LiuJieStatusFrame

/**
 *  计算文本的尺寸
 *
 *  @param text    文本内容
 *  @param font    文本字体
 *  @param maxSize 文本最大显示的尺寸
 *
 *  @return 文本的尺寸
 *  (如果文本实际的尺寸没有达到maxSize,则返回文本的实际尺寸;如果文本实际尺寸超过了maxSize,则返回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)setStatus:(LiuJieStatus *)status{
    // 固定写法
    _status = status;
    
    // 子控件之间的间距
    CGFloat padding = 10;
    
    // 1,头像
    CGFloat iconX = padding;
    CGFloat iconY = padding;
    CGFloat iconW = 30;
    CGFloat iconH = 30;
    // 这里为什么不使用self.iconF?因为使用的readOnly,没有set方法
    _iconF = CGRectMake(iconX, iconY, iconW, iconH);
    
    // 2,昵称
    // 计算昵称的尺寸
    CGSize nameSize = [self sizeWithText:status.name font:LiuJieNameFont maxSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];
    // 昵称的X值 = 头像的最大的X值 + 间距
    CGFloat nameX = CGRectGetMaxX(_iconF) + padding;
    // 昵称在头像的右边,且昵称在Y方向相对于头像是居中的
    CGFloat nameY = iconY + (iconH - nameSize.height) * 0.5;
    _nameF = CGRectMake(nameX, nameY, nameSize.width, nameSize.height);
    
    // 3,vip会员图标
    CGFloat vipX = CGRectGetMaxX(_nameF) + padding;
    CGFloat vipY = nameY;
    // 根据图片的像素来确定
    CGFloat vipW = 14;
    CGFloat vipH = 14;
    _vipF = CGRectMake(vipX, vipY, vipW, vipH);
    
    // 4,正文
    CGFloat textX = iconX;
    CGFloat textY = CGRectGetMaxY(_iconF) + padding;
    // 计算正文的尺寸
    CGSize textSize = [self sizeWithText:status.text font:LiuJieTextFont maxSize:CGSizeMake(300, MAXFLOAT)];
    CGFloat textW = textSize.width;
    CGFloat textH = textSize.height;
    _textF = CGRectMake(textX, textY, textW, textH);
    
    // 5,配图
    if (self.status.picture) {// 如果有配图
        CGFloat pictureX = textX;
        CGFloat pictureY = CGRectGetMaxY(_textF) + padding;
        CGFloat pictureW = 100;
        CGFloat pictureH = 100;
        _pictureF = CGRectMake(pictureX, pictureY, pictureW, pictureH);
        
        // 如果有配图,那么cell的高度就为配图的最大的Y值 + padding
        _cellHeight = CGRectGetMaxY(_pictureF) + padding;
        
    }else{
        
        // 如果没有配图,那么cell的高度就为正文的最大的Y值 + padding
        _cellHeight = CGRectGetMaxY(_textF) + padding;
    }
    
}

@end
//
//  LiuJieStatusCell.h
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
      
      
       
       
@class LiuJieStatusFrame;

@interface LiuJieStatusCell : UITableViewCell

/**
 *  提供一个静态方法返回cell
 */
+ (instancetype)cellWithTableView:(UITableView *)tableView;

/**
 *  要根据statusFrame中的数据来设置cell中子控件的数据
 */
@property (nonatomic,strong)LiuJieStatusFrame *statusFrame;

@end
//
//  LiuJieStatusCell.m
//  02-微博
//
//  Created by XinYou on 15-3-2.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//


// 昵称的字体
#define LiuJieNameFont [UIFont systemFontOfSize:14]
// 正文的字体
#define LiuJieTextFont [UIFont systemFontOfSize:15]

#import "LiuJieStatusCell.h"
#import "LiuJieStatus.h"
#import "LiuJieStatusFrame.h"

@interface LiuJieStatusCell()
/**
 *  头像
 */
@property (nonatomic,weak) UIImageView *iconView;
/**
 *  昵称
 */
@property (nonatomic,weak) UILabel *nameView;
/**
 *  会员图标
 */
@property (nonatomic,weak) UIImageView *vipView;
/**
 *  正文
 */
@property (nonatomic,weak) UILabel *textView;
/**
 *  配图
 */
@property (nonatomic,weak) UIImageView *pictureView;

@end

@implementation LiuJieStatusCell

/**
 *  构造方法,在初始化对象的时候会调用
 *  一般在这个方法中添加需要显示的子控件
 *  在这个方法中,我们只初始化控件,设置控件的不变属性,其他属性不设置,数据也不设置
 */
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // 1,设置头像
        UIImageView *iconView = [[UIImageView alloc] init];
        // 注意这里是添加到cell的contentView中
        [self.contentView addSubview:iconView];
        self.iconView = iconView;
     
        // 2,设置昵称
        UILabel *nameView = [[UILabel alloc] init];
        // 因为字体只需设置一次,属于不变的属性,所以在这里设置
        nameView.font = LiuJieNameFont;
        [self.contentView addSubview:nameView];
        self.nameView = nameView;
        
        // 3,设置vip会员图标
        UIImageView *vipView = [[UIImageView alloc] init];
        // 因为会员图标都是一样的,属于不变的属性
        // 我们在后面的代码中再控制会员图标的显示(如果是会员就显示,不是会员就隐藏)
        vipView.image = [UIImage imageNamed:@"vip"];
        [self.contentView addSubview:vipView];
        self.vipView = vipView;
        
        // 4,设置正文
        UILabel *textView = [[UILabel alloc] init];
        // 设置UILabel有多少行,如果设置为0,则文本的总长度决定行数
        textView.numberOfLines = 0;
        // 设置字体
        textView.font = LiuJieTextFont;
        [self.contentView addSubview:textView];
        self.textView = textView;
        
        // 5,设置配图
        UIImageView *prictureView = [[UIImageView alloc] init];
        [self.contentView addSubview:prictureView];
        self.pictureView = prictureView;
    }
    return self;
    
    // 由上面的代码可以看出,在这个方法中我们初始化了要显示的子控件,
    // 但是并没有设置子控件的尺寸
}

- (void)setStatusFrame:(LiuJieStatusFrame *)statusFrame{
    // 固定写法
    _statusFrame = statusFrame;

    // 1,设置cell中各个子控件的数据
    [self settingData];
    
    // 2,设置cell中各个子控件的frame
    [self settingFrame];
}

/**
 *  设置cell中各个子控件的数据
 */
- (void)settingData{
    
    // 微博数据
    LiuJieStatus *status = self.statusFrame.status;
    
    // 1,设置头像
    self.iconView.image = [UIImage imageNamed:status.icon];
    
    // 2,设置昵称
    self.nameView.text = status.name;
    
    // 3,设置vip会员图标的显示和隐藏
    if (status.vip) {// 如果是vip
        // 显示vip图标
        self.vipView.hidden = NO;
        // 昵称为红色
        self.nameView.textColor = [UIColor redColor];
    }else{// 如果不是vip
        // 隐藏vip图标
        self.vipView.hidden = YES;
        // 昵称为黑色
        self.nameView.textColor = [UIColor blackColor];
    }
    
    // 4,设置正文
    self.textView.text = status.text;
    
    // 5,设置配图
    if (status.picture) {// 有配图
        self.pictureView.hidden = NO;
        self.pictureView.image = [UIImage imageNamed:status.picture];
    }else{// 没有配图
        self.pictureView.hidden = YES;
    }
    
}
/**
 *  设置cell中各个子控件的尺寸
 */
- (void)settingFrame{
    // 1,头像
    self.iconView.frame = self.statusFrame.iconF;
    
    // 2,昵称
    self.nameView.frame = self.statusFrame.nameF;
    
    // 3,会员图标
    self.vipView.frame = self.statusFrame.vipF;
    
    // 4,正文
    self.textView.frame = self.statusFrame.textF;
    
    // 5,配图
    if (self.statusFrame.status.picture) {// 有配图
        
        self.pictureView.frame = self.statusFrame.pictureF;
    }
}

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *ID = @"status";
    
    LiuJieStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if (cell == nil) {
        cell = [[LiuJieStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    
    return cell;
}

@end

      
      
     
     
    
    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值