UITableView介绍 之 复杂cell的高度计算

复杂cell的高度计算

  • 实现了多行文字的自适应
  • 实现了图文混排的自适应

20160312224113988

  在我的日常开发中经常会遇到cell内容比较复杂的情况,复杂的cell势必会有cell高度不相同的情况,这种需求往往是比较蛋疼的。但是没关系只要掌握了其中的原理剩下的就只是体力活了。本文采用传统方式纯代码布局来计算cell的高度值,如果精力允许下篇介绍AutoLayout自动布局下的cell高度的计算。

ViewController中的主要代码实现

为了方便起见本ViewController继承自UITableViewController具体实现代码如下:

//
//  MTableViewController.m
//  cell计算
//
//  Created by code_xq on 16/3/12.
//  Copyright © 2016年 code_xq. All rights reserved.
//

#import "MTableViewController.h"
#import "MTableViewCell.h"
#import "DataModel.h"

static NSString *ID = @"cell";

@interface MTableViewController ()

@property (nonatomic, strong) NSMutableArray *dataSource;

@end

@implementation MTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = @"cell的高度计算";
    // 去除tableView的默认下划线
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.9];
    
    // 注册cell
    [self.tableView registerClass:[MTableViewCell class] forCellReuseIdentifier:ID];
    
    // 异步获取数据
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *path = [[NSBundle mainBundle] pathForResource:@"cellList.plist" ofType:nil];
        NSArray *array = [NSArray arrayWithContentsOfFile:path];
        
        for (NSDictionary *dict in array) {
            DataModel *dm = [DataModel initWith:dict];
            [self.dataSource addObject:dm];
        }
        // 造数据
        [self.dataSource addObjectsFromArray:self.dataSource];
        // 在主线程中刷新数据
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    });
}

#pragma mark - Table view data source

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.dataModel = self.dataSource[indexPath.row];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    DataModel *dm = self.dataSource[indexPath.row];
    return dm.cellHeight;
}

/**
 *  给出cell的估计高度,主要目的是优化cell高度的计算次数
 */
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 200;
}

/**
 * 初始化数据
 */
- (NSMutableArray *)dataSource {
    if (_dataSource == nil) {
        _dataSource = [NSMutableArray array];
    }
    
    return _dataSource;
}

@end

这段代码是初始化tableView的常规做法,值得注意的是UITableView的
estimatedHeightForRowAtIndexPath 这个方法给出cell的预估值,如果没有实现这个方法,tableView内部会一次性将所有的cell的高度全部计算出来,有了这个方法会对tableView的性能有所提高,这个方法的返回值理论上可以是任意值。

Model数据的代码实现

//
//  DataModel.h
//  cell计算
//
//  Created by code_xq on 16/3/12.
//  Copyright © 2016年 code_xq. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface DataModel : NSObject

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

/** 图标*/
@property (nonatomic, copy) NSString *icon;

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

/** 用户名*/
@property (nonatomic, strong) NSString *name;

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

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

@end

/***********************类的实现*********************/

#import "DataModel.h"

@implementation DataModel

+ (instancetype)initWith:(NSDictionary *)dict {
    DataModel *dm = [[self alloc] init];
    [dm setValuesForKeysWithDictionary:dict];
    return dm;
}
@end

数据是从plist中获取直接转换成DataModel对象的,这里多了一个cellHeight的属性用来存放cell的高度。

重头戏自定义cell的代码实现

//
//  MTableViewCell.h
//  cell计算
//
//  Created by code_xq on 16/3/12.
//  Copyright © 2016年 code_xq. All rights reserved.
//

#import <UIKit/UIKit.h>
@class DataModel;
@interface MTableViewCell : UITableViewCell

/** 数据模型*/
@property (nonatomic, strong) DataModel *dataModel;

@end

/***********************类的实现*********************/


#import "MTableViewCell.h"
#import "UIView+Expand.h"
#import "DataModel.h"

#define SCWIDTH [UIScreen mainScreen].bounds.size.width
#define SCHEIGHT [UIScreen mainScreen].bounds.size.height

static CGFloat const margin = 10;

@interface MTableViewCell()

@property (nonatomic, weak) UIImageView *imageIcon;
@property (nonatomic, weak) UILabel *labelName;
@property (nonatomic, weak) UILabel *labelContent;
@property (nonatomic, weak) UIImageView *picView;
@end

@implementation MTableViewCell


- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setUpView];
    }
    return self;
}


- (void)setUpView {
    // 用户头像
    UIImageView *imageIcon = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
    imageIcon.left = margin;
    imageIcon.top = margin;
    self.imageIcon = imageIcon;
    [self.contentView addSubview:imageIcon];
    
    // 用户名
    CGFloat nameW = SCWIDTH - imageIcon.width - 3 * margin;
    UILabel *labelName = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, nameW, 30)];
    labelName.left = imageIcon.right + margin;
    labelName.top = margin;
    labelName.font = [UIFont systemFontOfSize:20];
    self.labelName = labelName;
    [self.contentView addSubview:labelName];
    
    // 文字内容
    UILabel *labelContent = [[UILabel alloc] initWithFrame:CGRectMake(margin, 0, SCWIDTH - 20 , 30)];
    labelContent.top = imageIcon.bottom + margin;
    // 设置显示多行文字
    labelContent.lineBreakMode = NSLineBreakByCharWrapping;
    labelContent.numberOfLines = 0;
    labelContent.font = [UIFont systemFontOfSize:15];
    self.labelContent = labelContent;
    [self.contentView addSubview:labelContent];
    
    // 图片
    UIImageView *picView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 120, 90)];
    picView.left = margin;
    self.picView = picView;
    [self.contentView addSubview:picView];
}


- (void)setFrame:(CGRect)frame {
    frame = CGRectMake(frame.origin.x, frame.origin.y + 10, frame.size.width, frame.size.height - 10);
    [super setFrame:frame];
}


- (void)setDataModel:(DataModel *)dataModel {
    _dataModel = dataModel;
    // 设置用户头像
    self.imageIcon.image = [UIImage imageNamed: dataModel.icon];
    // 设置用户名
    self.labelName.text = dataModel.name;
    
    // 计算文字内容的高度
    CGFloat height =  [dataModel.text boundingRectWithSize:CGSizeMake(SCWIDTH - 2 * margin, CGFLOAT_MAX)
                                                   options:NSStringDrawingUsesLineFragmentOrigin
                                                attributes:@{NSFontAttributeName : self.labelContent.font}
                                                   context:nil].size.height;
    self.labelContent.height = height;
    self.labelContent.text = dataModel.text;
    
    // 设置图片内容
    if (dataModel.picture) {
        self.picView.hidden = NO;
        self.picView.top = self.labelContent.bottom + margin;
        self.picView.image = [UIImage imageNamed:dataModel.picture];
        dataModel.cellHeight = self.picView.bottom + 2 * margin;
    } else {
        self.picView.hidden = YES;
        dataModel.cellHeight = self.labelContent.bottom + 2 * margin;
    }
    
}

@end

为了布局方便自己给UIView写了个分类可以很容易获取view的left、top、right、bottom的值,好了到此复杂cell的高度计算就讲完了,如果有机会继续讲述AutoLayout自动布局下的cell高度的计算。

转载于:https://www.cnblogs.com/code-xq/p/5270932.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值