UITableView 高级

宗政招
2023-12-01

自定义Cell

1.创建UITableViewCell的子类

2.将添加到UITableViewCell的子视图设置为属性 同时将数据类也作为属性 方便给子视图进行赋值

#import <UIKit/UIKit.h>
#import "CellModel.h"
@interface NewsTableViewCell : UITableViewCell

@property (nonatomic ,retain) UILabel *titleLabel;

@property (nonatomic, retain) UILabel *summaryLabel;
// 选中图片
@property (nonatomic, retain) UIImageView *imageV;

@property (nonatomic, retain) CellModel *model;

@end

3.重写自定义初始化方法

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

        [self addLabel];
    }
    return self;
}

// 添加子视图
- (void)addLabel
{
    self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake((kScreenWidth - 300) / 2, 20, 300, 40)];
    self.titleLabel.backgroundColor = [UIColor orangeColor];
    self.titleLabel.numberOfLines = -1;
    self.titleLabel.font = [UIFont systemFontOfSize:16];
    // 注意给UITableViewCell及其子类添加子视图时 需要添加到self.contentView上
    [self.contentView addSubview:self.titleLabel];
    [_titleLabel release];

    self.summaryLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.titleLabel.left, self.titleLabel.bottom + 10, self.titleLabel.width, self.titleLabel.height)];
    self.summaryLabel.backgroundColor = [UIColor grayColor];
    // 多行显示
    self.summaryLabel.numberOfLines = -1;
    // 设置字体大小
    self.summaryLabel.font = [UIFont systemFontOfSize:16];
    [self.contentView addSubview:self.summaryLabel];
    [_summaryLabel release];

    self.imageV = [[UIImageView alloc] initWithFrame:CGRectMake(340, self.titleLabel.top + 5, 30, 30)];

    [self.contentView addSubview:self.imageV];
    [_imageV release];
}

4.重写model属性的setter方法

- (void)setModel:(CellModel *)model
{
    if (_model != model) {
        [_model release];
        _model = [model retain];
    }
    // 在给model赋值的同时 给子视图进行赋值
    self.titleLabel.text = model.title;
    self.summaryLabel.text = model.summary;

    // 在赋值的同时 改变label的高度(见下文)
    // 获取字符串高度
    CGFloat summaryHeight = [NewsTableViewCell cellHeightForModel:model];
    // 改变一下label的高度
    self.summaryLabel.height = summaryHeight;

}

5.在添加cell的方法中用该类初始化对象cell

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"MyCell";
    NewsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (cell == nil) {
        cell = [[[NewsTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier] autorelease];
    }
    CellModel *model = self.arrData[indexPath.row];
    // 直接赋值 将具体赋值过程封装在NewsTableViewCell类中进行
    cell.model = model;


    return cell;
}

计算字符串完全显示需要的高度

用于改变存放字符串的label的高度, 通常在UITableViewCell的子类中实现

// 计算字符串的高度(类方法)
+ (CGFloat)cellHeightForModel:(CellModel *)model
{
    // 创建字体大小的字典
    // 这里设置了字体大小后 需要label的font属性做相应的改变
    NSDictionary *fontDic = @{NSFontAttributeName: [UIFont systemFontOfSize:16]};
    CGRect textRect = [model.summary boundingRectWithSize:CGSizeMake(300, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:fontDic context:nil];
    return textRect.size.height;
}

当然 不光要改变label的高度 同时需要改变cell的高度

// 行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CellModel *model = self.arrData[indexPath.row];
    CGFloat tempHeight = [NewsTableViewCell cellHeightForModel:model];
    // 上边距 + tilteLabel + 中间距离 + summaryLabel + 下边距
    return 20 + 40 + 10 + tempHeight + 20;
}

点击cell 改变cell上的子视图

给cell 添加一个UIImageView 点击cell时 UIImageView.image 变成选中图片 再次点击cell 时UIImageView.image 变回未选中图片

当然不能直接在方法中更改图片 这样子再次点击无法变回未选中图片

因此需要给model添加 isSelected 属性 来记录对应的cell的点击状态

在tableView 用 CellModel 类 “获取” 数据文件的字典数据的同时 应该给model.isSelected属性赋一个初值 而cell一开始应该显示未选中图片 所以:model.isSelect = NO;

- (void)setUpData
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"NewsData" ofType:@"plist"];
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
    NSArray *values = dic[@"news"];
    self.arrData = [NSMutableArray array];
       for (int i = 0; i < values.count; i++) {
          CellModel *model = [[CellModel alloc] init];
          [model setValuesForKeysWithDictionary:values[i]];
           ***model.isSelect = NO;***
          [self.arrData addObject:model];
          [model release];
    }
}

当然此时为了使cell在程序运行开始时呈现未选中图片 需要在给cell.model 赋值的同时 给 imageView添加一个图片 但是并不是直接给他一张未选中图片 如果这样做了 那么从重用集合中取出的cell即使是选中状态 也会在 重新赋值时变回未选中状态

我们不想在屏幕上滑时出现这样的问题 所以需要在赋值过程中判断一下(赋值过程当然还在cell的子类中进行)

- (void)setModel:(CellModel *)model
{
    if (_model != model) {
        [_model release];
        _model = [model retain];
    }
    // 利用model中的点选状态 解决cell复用的问题
    // 需要每次被复用的cell 再进行一次与状态对应的赋值
    if (model.isSelect == YES) {
        self.imageV.image = [UIImage imageNamed:@"select"];
    }else{
        self.imageV.image = [UIImage imageNamed:@"cancel"];
    }

}

在点击方法中根据选中属性model.isSelect 来给cell 的 ImageView 更换图片

// cell 点击的方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 取出被点击的cell
    // 更改cell 图片
    NewsTableViewCell *cell = (NewsTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
    CellModel *model = self.arrData[indexPath.row];

    // 更改点击的状态
    model.isSelect = !model.isSelect;

    if (model.isSelect == YES) {
        cell.imageV.image = [UIImage imageNamed:@"select"];
    }else{
        cell.imageV.image = [UIImage imageNamed:@"cancel"];
    } 
}
 类似资料: