iOS开发iOS学习笔记iOS开发记录

iOS 纯代码实现自定义Cell

2018-05-23  本文已影响165人  奋拓达

自适应TableViewCell高度计算优化方案:

1、TableView自定义控件的步骤:

1. 重写initWithFrame、awakeFromNib等初始化方法
2. 重写LayoutSubView方法布局子控件的frame
3. 为cell添加一个模型属性,并实现setModel方法,用于给子控件赋值
4. 提供一个便利的初始化方法用来快速初始化自定义的控件

2、计算UILabel的高度及尺寸

1、计算UILabel的尺寸是和字体相关的,不同的字体类型,字体大小 这些因素都会影响UILabel的宽度,一次计算尺寸的时候字体参数是必须的。
2、计算单行的UILabel:sizeWithAttributes:@{NSFontAttributeName:[UIFont systemOfSize:17.f]}
3、计算多行的Label:和计算单行Label的方法不同,因为是多行需要计算UILabel究竟有多宽换行,同样的内容长度,宽度越宽,高度就越低,所以必须制定需要换行的最大的约束尺寸,高度是指在多宽的时候换行,高度是指实际计算后所返回的最大高度,如果设置的值比实际的值要小,只能返回所设置值大小,所以这个值一般都写很大的一个值,可以使用一个常量MAXFloat表示。
boundingRectWithSize:options:attributes:context;
4、rowHeight属性是UITableView的属性,而不是UITableViewCell的属性

3、调用顺序

- viewDidLoad
- tableView:numberOfRowsInSection:
- tableView:heightForRowAtIndexPath: // 该方法一直循环调用N次,因初始化控件时需要知道contentSize的尺寸,只有知道所有cell的高度,才能计算总高度,根据contentSize的高度也能确定滚动条的高度
- tableView:cellForRowAtIndexPath: // 该方法一直循环调用N次
- initWithStyle:reuseIdentifier:
- setModel:
- layoutSubviews // 该方法一直循环调用N次需要注意的是自定义cell是先设置模型数据,后调用layoutSubviews布局子视图
模型类的设置
#import <Foundation/Foundation.h>

#import "CellFrame.h"
@interface Status : NSObject

@property (copy, nonatomic) NSString *icon;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic, getter=isVip) BOOL vip;
@property (copy, nonatomic) NSString *text;
@property (copy, nonatomic) NSString *picture;

@property (strong, nonatomic) CellFrame *cellFrame;

@end
//-----------------------------------------
#import "Status.h"

@implementation Status

- (CellFrame *)cellFrame {
    if (_cellFrame == nil) {
        _cellFrame = [[CellFrame alloc] initWithStatus:self];
    }
    
    return _cellFrame;
}

@end

对CellFrame的计算
#import <UIKit/UIKit.h>

@class Status;

@interface CellFrame : NSObject

@property (assign, nonatomic) CGRect headFrame;
@property (assign, nonatomic) CGRect nicknameFrame;
@property (assign, nonatomic) CGRect vipFrame;
@property (assign, nonatomic) CGRect contentFrame;
@property (assign, nonatomic) CGRect pictureFrame;
@property (assign, nonatomic) CGFloat cellHeight;

- (instancetype)initWithStatus:(Status *)status;
@end

//------------------------------------------
#import "CellFrame.h"
#import "Status.h"

@interface CellFrame ()
@property (weak, nonatomic) Status *status;
@end

@implementation CellFrame

- (instancetype)initWithStatus:(Status *)status {
    if (self = [super init]) {
        _status = status;
    }
    
    return self;
}

- (CGFloat)cellHeight {
    if (_cellHeight == 0) {
        // head frame
        CGFloat margin = 10;
        self.headFrame = CGRectMake(margin, margin, 50, 50);
        
        // nickename frame
        CGFloat nickenameLabelX = CGRectGetMaxX(self.headFrame) + margin;
        CGFloat nickenameLabelY = CGRectGetMinY(self.headFrame);
        CGSize nickenameLabelSize = [self.status.name sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0f]}];
        self.nicknameFrame = CGRectMake(nickenameLabelX, nickenameLabelY, nickenameLabelSize.width, nickenameLabelSize.height);
        
        // vip frame
        if (self.status.isVip) {
            CGFloat vipImageViewX = CGRectGetMaxX(self.nicknameFrame) + margin;
            CGFloat vipImageViewY = CGRectGetMinY(self.nicknameFrame);
            self.vipFrame = CGRectMake(vipImageViewX, vipImageViewY, 14, 14);
        }
        
        // content frame
        CGFloat contentLabelX = CGRectGetMinX(self.headFrame);
        CGFloat contentLabelY = CGRectGetMaxY(self.headFrame) + margin;
        CGRect contentRect = [self.status.text boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 2 * margin, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.f]} context:nil];
        self.contentFrame = CGRectMake(contentLabelX, contentLabelY, contentRect.size.width, contentRect.size.height);
        
        // picture frame
        if (self.status.picture != nil) {
            CGFloat pictureLabelX = CGRectGetMinX(self.contentFrame);
            CGFloat pictureLabelY = CGRectGetMaxY(self.contentFrame) + margin;
            self.pictureFrame = CGRectMake(pictureLabelX, pictureLabelY, 70, 100);
            self.cellHeight = CGRectGetMaxY(self.pictureFrame) + margin;
        } else {
            self.cellHeight = CGRectGetMaxY(self.contentFrame) + margin;
        }

    }
    
    return _cellHeight;
}
@end
自定义Cell
#import <UIKit/UIKit.h>
#import "Status.h"
@interface TableViewCell : UITableViewCell

@property (strong, nonatomic) Status *status;

@end

#import "TableViewCell.h"

@interface TableViewCell ()

@property (weak, nonatomic) UIImageView *headImageView;
@property (weak, nonatomic) UILabel *nicknameLabel;
@property (weak, nonatomic) UIImageView *vipImageView;
@property (weak, nonatomic) UILabel *contentLabel;
@property (weak, nonatomic) UIImageView *pictureImageView;

@end

@implementation TableViewCell


// 1. 初始化子视图
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        // 头像
        UIImageView *headImageView = [[UIImageView alloc] init];
        [self.contentView addSubview:headImageView];
        self.headImageView = headImageView;
        
        // 昵称
        UILabel *nicknameLabel = [[UILabel alloc] init];
        nicknameLabel.font = [UIFont systemFontOfSize:17.f];
        [self.contentView addSubview:nicknameLabel];
        self.nicknameLabel = nicknameLabel;
        
        // 图标
        UIImageView *vipImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"vip"]];
        [self.contentView addSubview:vipImageView];
        self.vipImageView = vipImageView;
        
        // 正文
        UILabel *contentLabel = [[UILabel alloc] init];
        contentLabel.numberOfLines = 0;
        contentLabel.font = [UIFont systemFontOfSize:14.f];
        [self.contentView addSubview:contentLabel];
        self.contentLabel = contentLabel;
        
        // 配图
        UIImageView *pictureImageView = [[UIImageView alloc] init];
        [self.contentView addSubview:pictureImageView];
        self.pictureImageView = pictureImageView;
    }
    
    return self;
}


// 2. 布局子视图
- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.headImageView.frame = self.status.cellFrame.headFrame;
    self.nicknameLabel.frame = self.status.cellFrame.nicknameFrame;
    self.vipImageView.frame = self.status.cellFrame.vipFrame;
    self.contentLabel.frame = self.status.cellFrame.contentFrame;
    self.pictureImageView.frame = self.status.cellFrame.pictureFrame;
}


// 3. 填充数据
- (void)setStatus:(Status *)status {
    _status = status;
    
    // head
    self.headImageView.image = [UIImage imageNamed:status.icon];
    
    // nickname & vip
    self.nicknameLabel.text = status.name;
    if (status.isVip) {
        self.nicknameLabel.textColor = [UIColor orangeColor];
        self.vipImageView.hidden = NO;
    } else {
        self.nicknameLabel.textColor = [UIColor blackColor];
        self.vipImageView.hidden = YES;
    }
    
    // content
    self.contentLabel.text = status.text;
    
    // picture
    if (status.picture != nil) {
        self.pictureImageView.hidden = NO;
        self.pictureImageView.image = [UIImage imageNamed:status.picture];
    } else {
        self.pictureImageView.hidden = YES;
    }
}

@end
如何使用自定义的TableViewCell
#import <UIKit/UIKit.h>
@interface ViewController : UITableViewController

@end


#import "ViewController.h"
#import "TableViewCell.h"
#import "MJExtension.h"

@interface ViewController ()

@property (strong, nonatomic) NSArray *statuses;

@end

@implementation ViewController

static NSString *ID = @"ViewController";

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tableView registerClass:[TableViewCell class] forCellReuseIdentifier:ID];
    self.tableView.estimatedRowHeight = 200;
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%s", __func__);
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    cell.status = self.statuses[indexPath.row];
    
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%s", __func__);
    
    Status *status = self.statuses[indexPath.row];
    return status.cellFrame.cellHeight;
}

/**懒加载 */
- (NSArray *)statuses {
    if (_statuses == nil) {
        _statuses = [Status mj_objectArrayWithFilename:@"statuses.plist"];
    }
    
    return _statuses;
}
@end

上一篇 下一篇

猜你喜欢

热点阅读