iOS开发之自定义UITableViewCell

房东的猫 提交于 2019-12-26 19:09:00

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

等高的Cell

一、storyboard方式

  1. 创建一个继承自UITableViewCell的子类

  2. 在storyboard中

    - 往cell里面增加需要用到的子控件

        

      - 设置cell的重用标识

        

     - 设置cell的class为我刚才创建的那个Cell类型XXDealCell

    

    3. 在控制器中

      - 利用重用标识找到cell

      - 给cell传递模型数据

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.deals.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *ID = @"deal";
    
    XXDealCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //取出模型数据
    cell.deal = self.deals[indexPath.row];
    
    return cell;
}

     

    4.在XXDealCell中,将storyboard中的子控件连线到类扩展中,并且提供一个模型属性,重写模型的set方法,在这个方法中设置模型数据到子控件上。

//
//  XXDealCell.m
//  自定义等高的cell
//
//  Created by Daniel on 16/3/17.
//  Copyright © 2016年 Daniel. All rights reserved.
//

#import "XXDealCell.h"
#import "XXDeal.h"

@interface XXDealCell()

@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titleLable;
@property (weak, nonatomic) IBOutlet UILabel *priceLable;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLable;


@end

@implementation XXDealCell

- (void)setDeal:(XXDeal *)deal {
    
    _deal = deal;  
    //设置数据
    self.iconView.image = [UIImage imageNamed:deal.icon];
    self.titleLable.text = deal.title;
    self.priceLable.text = [NSString stringWithFormat:@"¥%@", deal.price]; 
    self.buyCountLable.text = [NSString stringWithFormat:@"%@人已购买", deal.buyCount];
    
}

@end



二、xib方式

1.创建一个继承自UITableViewCell的子类,比如XXDealCell

2.创建一个xib文件(文件名建议跟cell的类名一样),比如XXDealCell.xib,拖拽一个UITableViewCell出来,修改cell的class为XXDealCell,设置cell的重用标识,往cell中添加需要用到的子控件

这两步和storyboard方式都是大同小异。

3.在控制器中,利用registerNib...方法注册xib文件,利用重用标识找到cell(如果没有注册xib文件,就需要手动去加载xib文件),给cell传递模型数据。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XXDealCell class]) bundle:nil] forCellReuseIdentifier:@"deal"];
    
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *ID = @"deal";
    
    XXDealCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //如果不注册,就要这样手动加载xib
//    if(cell == nil) {
//        cell = [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([XXDealCell class]) owner:nil options:nil]lastObject];
//    }
    
    //取出模型数据
    cell.deal = self.deals[indexPath.row];

    
    return cell;
}

4.在XXDealCell中,将xib中的子控件连线到类扩展中,需要提供一个模型属性,重写模型的set方法,在这个方法中设置模型数据到子控件上,也可以将创建获得cell的代码封装起来(比如cellWithTableView:方法)

//
//  XXDealCell.m
//  自定义等高的cell
//
//  Created by Daniel on 16/3/17.
//  Copyright © 2016年 Daniel. All rights reserved.
//

#import "XXDealCell.h"
#import "XXDeal.h"

@interface XXDealCell()

@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titleLable;
@property (weak, nonatomic) IBOutlet UILabel *priceLable;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLable;


@end

@implementation XXDealCell

- (void)setDeal:(XXDeal *)deal {
    
    _deal = deal;
    
    //设置数据
    self.iconView.image = [UIImage imageNamed:deal.icon];
    
    self.titleLable.text = deal.title;
    
    self.priceLable.text = [NSString stringWithFormat:@"¥%@", deal.price];
    
    self.buyCountLable.text = [NSString stringWithFormat:@"%@人已购买", deal.buyCount];
    
    
}

+ (instancetype)cellWithTableView:(UITableView *) tableView {
    
    static NSString *ID = @"deal";
    
    XXDealCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if(cell == nil) {
        cell = [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([XXDealCell class]) owner:nil options:nil]lastObject];
    }
    
    return cell;
    
}

@end
- (void)viewDidLoad {
    [super viewDidLoad];
    
//    [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XXDealCell class]) bundle:nil] forCellReuseIdentifier:@"deal"];
    
}



#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.deals.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    XXDealCell *cell = [XXDealCell cellWithTableView:tableView];
    
    //取出模型数据
    cell.deal = self.deals[indexPath.row];

    
    return cell;
}



三、代码方式

-------------使用frame

1.创建一个继承自UITableViewCell的子类,比如XXDealCell

- 在initWithStyle:reuseIdentifier:方法中添加子控件,设置子控件的初始化属性(比如文字颜色、字体)等

- 在layoutSubviews方法中设置子控件的frame

- 需要提供一个模型属性,重写模型的setter方法,在这个方法中设置模型数据到子控件

//1、在initWithStyle:reuseIdentifier:方法中添加子控件
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if(self == [super initWithStyle:style reuseIdentifier:reuseIdentifier ]) {
        
        UIImageView *iconView = [[UIImageView alloc]init];
        [self.contentView addSubview:iconView];
        self.iconView = iconView;
        
        UILabel *titleLable = [[UILabel alloc]init];
        [self.contentView addSubview:titleLable];
        self.titleLable = titleLable;
        
        UILabel *priceLable = [[UILabel alloc]init];
        [self.contentView addSubview:priceLable];
        priceLable.textColor = [UIColor orangeColor];
        self.priceLable = priceLable;

        
        UILabel *buyCountLable = [[UILabel alloc]init];
        [self.contentView addSubview:buyCountLable];
        buyCountLable.textAlignment = NSTextAlignmentRight;
        buyCountLable.font = [UIFont systemFontOfSize:11];
        buyCountLable.textColor = [UIColor lightGrayColor];
        self.buyCountLable = buyCountLable;

    }
    return self;
}

//2、在layoutSubviews方法中设置子控件的frame
- (void)layoutSubviews {
    
    [super layoutSubviews];
    
    //iconView
    CGFloat iconX = 10;
    CGFloat iconY = 10;
    CGFloat iconW = 100;
    CGFloat iconH = self.contentView.frame.size.height - 2 * iconY;
    self.iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
    
    //titleLable
    CGFloat titleX = CGRectGetMaxX(self.iconView.frame) + 10;
    CGFloat titleY = iconY;
    CGFloat titleW = self.contentView.frame.size.width - titleX - 10;
    CGFloat titleH = 20;
    self.titleLable.frame = CGRectMake(titleX, titleY, titleW, titleH);
    
    //priceView
    CGFloat priceX = titleX;
    CGFloat priceH = 20;
    CGFloat priceY = self.contentView.frame.size.height - priceH - 10;
    CGFloat priceW = 70;
    self.priceLable.frame = CGRectMake(priceX, priceY, priceW, priceH);
    
    //buyCountView
    CGFloat buyH = priceH;
    CGFloat buyY = self.contentView.frame.size.height - 10 - buyH;
    CGFloat buyX = priceX + priceW + 10;
    CGFloat buyW = self.contentView.frame.size.width - buyX - 10;
    
    self.buyCountLable.frame = CGRectMake(buyX, buyY, buyW, buyH);

    
}


//3、重写模型的setter方法
- (void)setDeal:(XXDeal *)deal {
    
    _deal = deal;
    
    //设置数据
    self.iconView.image = [UIImage imageNamed:deal.icon];
    
    self.titleLable.text = deal.title;
    
    self.priceLable.text = [NSString stringWithFormat:@"¥%@", deal.price];
    
    self.buyCountLable.text = [NSString stringWithFormat:@"%@人已购买", deal.buyCount];
    
    
}

2.在控制器中,利用registerClass...方法注册XMGDealCell类,利用重用标识找到cell(如果没有注册类,就需要手动创建cell,给cell传递模型数据,也可以将创建获得cell的代码封装起来(比如cellWithTableView:方法)。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    XXDealCell *cell = [XXDealCell cellWithTableView:tableView];
    //取出模型数据
    cell.deal = self.deals[indexPath.row];
    return cell;
}


---------------------使用autoLayout

与使用frame不同的是:在initWithStyle:reuseIdentifier:方法中添加子控件后直接添加约束,然后不需要layoutSubviews方法了。其他都是一样的,添加约束使用Masonry。

//1、在initWithStyle:reuseIdentifier:方法中添加子控件
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if(self == [super initWithStyle:style reuseIdentifier:reuseIdentifier ]) {
        
        CGFloat margin = 10;
        
        UIImageView *iconView = [[UIImageView alloc]init];
        [self.contentView addSubview:iconView];
        self.iconView = iconView;
        [iconView makeConstraints:^(MASConstraintMaker *make) {
            make.width.equalTo(100);
            make.left.top.equalTo(self.contentView).offset(margin);
            make.bottom.equalTo(self.contentView).offset(-margin);
        }];
        
        UILabel *titleLable = [[UILabel alloc]init];
        [self.contentView addSubview:titleLable];
        self.titleLable = titleLable;
        [titleLable makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(iconView.right).offset(margin);
            make.top.equalTo(iconView);
            make.right.equalTo(self.contentView).offset(-margin);
        }];
        
        UILabel *priceLable = [[UILabel alloc]init];
        [self.contentView addSubview:priceLable];
        priceLable.textColor = [UIColor orangeColor];
        self.priceLable = priceLable;
        [priceLable makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(titleLable);
            make.bottom.equalTo(iconView);
        }];
        
        UILabel *buyCountLable = [[UILabel alloc]init];
        [self.contentView addSubview:buyCountLable];
        buyCountLable.textAlignment = NSTextAlignmentRight;
        buyCountLable.font = [UIFont systemFontOfSize:11];
        buyCountLable.textColor = [UIColor lightGrayColor];
        self.buyCountLable = buyCountLable;
        [buyCountLable makeConstraints:^(MASConstraintMaker *make) {
            make.bottom.equalTo(priceLable);
            make.right.equalTo(self.contentView).offset(-margin);
            make.left.equalTo(priceLable).offset(margin);
        }];

    }
    return self;
}



非等高cell

  1. xib自定义非等高cell

- 在模型中增加一个cellHeight属性,用来存放对应cell的高度

/**
 *  cell的高度
 */
@property(assign, nonatomic)CGFloat cellHeight;

- 在cell的模型属性setter方法中调用[self layoutIfNeed]方法强制布局,然后计算出模型的cellheight属性值

//强制布局
[self layoutIfNeeded];

- 在控制器中实现tableView:estimatedHeightForRowAtIndexPath:方法,返回一个估计高度

/**
 *  返回每一个cell的估计高度
 *
 *  @param tableView
 *  @param indexPath
 *
 *  @return 只要返回了估计高度,tableView就会先调用tableView:cellForRowAtIndexPath:方法创建cell
 *          再调用tableView:heightForRowAtIndexPath:方法获取cell的真实高度
 */
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100;
}

- 在控制器中实现tableView:heightForRowAtIndexPath:方法,返回cell的真实高度(模型中的cellHeight属性)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    XXStatusCell *cell = [XXStatusCell cellWithTableView:tableView];
    
    //设置数据
    cell.status = self.statuses[indexPath.row];
    
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    XXStatus *status = self.statuses[indexPath.row];
    return status.cellHeight;
}

2、storyboard方式自定义非等高cell

用storyboard和xib其实大同小异,直接在storyboard中添加子控件并添加约束,设置重用标识,修改cell的类,修改cell为动态创建类型。注意,如果Lable要显示多行的话,Lines要改为0,而且cell高度极端准确,要加一个方法:

- (void)awakeFromNib {
    self.contentLable.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
}

然后获取cell时直接在缓存池中根据重用标识去查找,其他的和xib方式一样。

+ (instancetype)cellWithTableView :(UITableView *)tableView {
    
    return [tableView dequeueReusableCellWithIdentifier:@"status"];
    
}


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!