UITableViewCell的自定义以及重用

在UITableView中,我们通常来展示各色各样的信息,这时,系统自带的cell形式就无法满足我们的需求了。此时,我们就需要用到自定义cell。

自定义cell

自定义的cell继承自UITableViewCell,同时,我们一般会声明一个模型类型的属性,我们通过重写这个属性的setter方法来对自定义cell上的控件进行UI展示。
自定义cell代码如下:

.h文件中

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell

//通常在cell中暴露一个属性接口,通过重写它的setter方法来完成对cell UI的布局。
@property (nonatomic, copy) NSString *stringModel;

@end

.m文件中

#import "CustomCell.h"

@interface CustomCell ()

//自定义cell所需展示的控件
@property (nonatomic, strong) UILabel *stringLabel;

@end

@implementation CustomCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.stringLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, 150, 30)];
        self.stringLabel.textColor = [UIColor redColor];
        [self.contentView addSubview:self.stringLabel];
    }
    return self;
}

- (void)setStringModel:(NSString *)stringModel
{
    self.stringLabel.text = stringModel;
}

@end

cell的重用

自定义cell很简单,但是怎么使用它才是最重要的。我们知道,UITableView会展示大量的数据,如果展示的数据过多的话,每条数据都会需要一个cell,这样就加大了内存的消耗。幸运的是,UITableView带有cell重用机制,通过cell的重新利用,最大程度的减小了cell的创建,从而减少内存的消耗。

现在推荐使用注册的方式来完成cell的重用。该机制首先将一个cell实例放入一个缓存池中,然后UITableView在需要cell时,首先从缓存池中通过注册cell时的reuseid来找寻相同类型的cell,如果找到cell,则使用它,如果没有找到,则创建cell。一个cell在屏幕中不展示后,cell会被重新放回缓存池中。这样就达到了重用的效果。

cell的注册

[self.tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"CustomCell"];

cell的使用

CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];

NSString *stringTemp = [[self.dataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];

cell.stringModel = stringTemp;

return cell;

总结

通过三篇博文,把UITableView的最常用的方法介绍了一遍,下面贴出源码。

自定义cell.h文件

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell

//通常在cell中暴露一个属性接口,通过重写它的setter方法来完成对cell UI的布局。
@property (nonatomic, copy) NSString *stringModel;

@end

自定义cell.m文件

#import "CustomCell.h"

@interface CustomCell ()

//自定义cell所需展示的控件
@property (nonatomic, strong) UILabel *stringLabel;

@end

@implementation CustomCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.stringLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, 150, 30)];
        self.stringLabel.textColor = [UIColor redColor];
        [self.contentView addSubview:self.stringLabel];
    }
    return self;
}

- (void)setStringModel:(NSString *)stringModel
{
    self.stringLabel.text = stringModel;
}

@end

ViewController.m文件

#import "ViewController.h"
#import "CustomCell.h"

@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
//声明控件
@property (nonatomic, strong) UITableView *tableView;

//声明存储数据的数据结构
@property (nonatomic, strong) NSMutableArray *dataArray;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化控件
    CGRect frame = CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

    self.tableView = [[UITableView alloc] initWithFrame:frame style:UITableViewStyleGrouped];

    [self.tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"CustomCell"];

    [self.view addSubview:self.tableView];


    //设置代理
    self.tableView.delegate = self;
    self.tableView.dataSource = self;

    //加载数据
    [self loadData];

    //创建用来改变编辑状态的按钮
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(rightBtnAction:)];
}

#pragma mark - 按钮事件 
- (void)rightBtnAction:(UIBarButtonItem *)sender
{
    if (self.tableView.editing == YES) {
        self.navigationItem.rightBarButtonItem.title = @"编辑";
    }else{
        self.navigationItem.rightBarButtonItem.title = @"完成";
    }
    self.tableView.editing = !self.tableView.editing;
}

#pragma mark - 加载数据
- (void)loadData
{
    for (int i = 0; i < 4; i++) {
        NSMutableArray *arrayTemp = [NSMutableArray array];
        for (int j = 0; j < 4; j++) {
            NSString *stringTemp = [NSString stringWithFormat:@"第%d块 第%d行", i, j];
            [arrayTemp addObject:stringTemp];
        }
        [self.dataArray addObject:arrayTemp];
    }
}


#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return self.dataArray.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[self.dataArray objectAtIndex:section] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];

    NSString *stringTemp = [[self.dataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];

    cell.stringModel = stringTemp;

    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //该条数据是这个块中最后一条数据
    if ([[self.dataArray objectAtIndex:indexPath.section] count] == 1) {
        //删除数据
        [self.dataArray removeObjectAtIndex:indexPath.section];
        //更新页面
        NSIndexSet *set = [NSIndexSet indexSetWithIndex:indexPath.section];
        [self.tableView deleteSections:set withRowAnimation:UITableViewRowAnimationRight];
    }else{
        //删除数据
        [[self.dataArray objectAtIndex:indexPath.section] removeObjectAtIndex:indexPath.row];
    //更新页面
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
    }
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    NSString *stringTemp = [[self.dataArray objectAtIndex:sourceIndexPath.section] objectAtIndex:sourceIndexPath.row];

    [[self.dataArray objectAtIndex:sourceIndexPath.section] removeObjectAtIndex:sourceIndexPath.row];
    [[self.dataArray objectAtIndex:destinationIndexPath.section] insertObject:stringTemp atIndex:destinationIndexPath.row];

    if ([[self.dataArray objectAtIndex:sourceIndexPath.section] count] == 0) {
        [self.dataArray removeObjectAtIndex:sourceIndexPath.section];
        [self.tableView reloadData];
    }
}

#pragma mark - 懒加载
- (NSMutableArray *)dataArray
{
    if (_dataArray == nil) {
        self.dataArray = [NSMutableArray array];
    }
    return _dataArray;
}

@end