iOS开发之UI篇(5)—— UITableView

一.基本概念

UITableView : UIScrollView : UIView : UIResponder : NSObject

从继承关系我们可以知道:UITableView可以滚动,具有view的性质,能响应UI事件等等


1. UITableView结构:

UITableView可以有很多个section(本文成为组),每个section分别由一个Header(组头)、一个Fooder(组尾)及若干个cell组成。


2. UITableView有两种风格:

typedef NS_ENUM(NSInteger, UITableViewStyle) {

    UITableViewStylePlain,

    UITableViewStyleGrouped

};

两种风格主要区别为:

没有设置Header(或Fooder)时,Plain风格会隐藏掉Header(或Fooder),而Grouped仍会显示一个默认高度值。


3. UITableViewCell有四种风格

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {

    UITableViewCellStyleDefault,   

    UITableViewCellStyleValue1,   

    UITableViewCellStyleValue2,   

    UITableViewCellStyleSubtitle   

};

如果你的UITableViewCell不显示image或者detailTextLabel,那么最好先检查一下注册的时候设置的style是否符合。


4. 重用cell

为什么要重用cell?

由于屏幕显示的cell有限,而当数据量大的时候,如果每个数据创建一个Cell,就会占很大内存。

重用cell机制是这样的:创建了屏幕内cell所需的个数+1个屏幕之外的cell,在满足显示效果的前提下尽可能降低消耗内存。

这种机制下默认有一个可变数组NSMutableArray* visiableCells用来保存当前显示的cell一个可变字典NSMutableDictionary* reusableTableCells用来保存可重复利用的cell(之所以用字典是因为可重用的cell有不止一种样式,我们需要根据它的reuseIdentifier,也就是所谓的重用标示符来查找是否有可重用的该样式的cell)

如何重用cell?

首先要创建一个有重用标识符reuseIdentifier的cell,这些cell会被保存到重用队列中去。当需要实例化cell的时候,首先根据reuseIdentifier去找对应的cell。

加载cell到重用队列有两种方法:

// 法1:使用tableView注册一个cell

[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"myCell"];

// 法2:在cell的配置代理方法创建一个cell

if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];

}

根据重用标识符reuseIdentifier实例化一个cell:

// 实例化一个UITableViewCell

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



二、简单用法

代码实例:

#define    TABLE_WIDTH      [UIScreen mainScreen].bounds.size.width

#define    TABLE_HEIGHT    [UIScreen mainScreen].bounds.size.height

#import "ViewController.h"

@interface ViewController () <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@property (nonatomic, strong, nullable) NSArray *digitalArr;

@property (nonatomic, strong, nullable) NSArray *letterArr;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    // 装载数据源

    self.digitalArr = @[@"0", @"1", @"2"];

    self.letterArr  = @[@"A", @"B", @"C"];

    // 添加tableView到self.view

    [self.view addSubview:self.tableView];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

}


#pragma mark - UITableViewDelegate

// cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return 60;

}

// Header高度

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {

    return 30;

}
// Footer高度

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    return 30;

}

// 选中了某个cell

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


}


#pragma mark - UITableViewDataSource

// Section数量

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 2;

}

// 对应Section中cell的个数

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return self.digitalArr.count;

            break;

        case 1:    // 字母组

            return self.letterArr.count;

            break;

        default:

            break;

    }

    return 0;

}

// Header标题

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return @"数字组头";

            break;

        case 1:    // 字母组

            return @"字母组头";

            break;

        default:

            break;

    }

    return nil;

}

// Footer标题

- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return @"数字组尾";

            break;

        case 1:    // 字母组

            return @"字母组尾";

            break;

        default:

            break;

    }

    return nil;

}

// cell

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // 实例化一个UITableViewCell

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

    // 由于已经注册过重用cell,所以这里不必判断是否存在

//    if (cell == nil) {

//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];

//    }

    // 设置cell相关属性

    switch (indexPath.section) {

        case 0:    // 数字组

            if (indexPath.row < self.digitalArr.count) {

                cell.textLabel.text = self.digitalArr[indexPath.row];

            }

            break;

        case 1:    // 字母组

            if (indexPath.row < self.letterArr.count) {

                cell.textLabel.text = self.letterArr[indexPath.row];

            }

            break;

        default:

            break;

    }

    // 返回cell

    return cell;

}


#pragma mark - 懒加载

- (UITableView *)tableView {

    if (_tableView == nil) {

      // 实例化一个UITableView

        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, TABLE_WIDTH, TABLE_HEIGHT)

                                                  style:UITableViewStylePlain];

        // 注册一个cell

        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"myCell"];

        // 设置代理

        _tableView.delegate = self;

        _tableView.dataSource = self;

    }

    return _tableView;

}

@end



三、cell的增、减、排序

当然,这里要说的操作并不是先改变数据源然后reloadData,而是通过对cell的操作,使整个过程具有动画效果、显得顺畅。

1. 添加

我们会新增两个代理,第一个是返回编辑操作的类型。有插入类型删除类型

先定义一个全局变量_isDelete用于标记是点击添加还是删除按钮:

- (IBAction)btnAdd:(UIButton *)sender {

    _isDelete = NO;    // 编辑类型:添加

    // 启动编辑(参数一:tableView是否正在编辑;参数二:是否动画)

    [self.tableView setEditing:!self.tableView.isEditing animated:YES];

}

调用方法setEditing: animated:后,接着来到代理方法:

// 返回操作类型(添加/删除)

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"返回操作类型");

    if (_isDelete) {

        return UITableViewCellEditingStyleDelete;

    }

    return UITableViewCellEditingStyleInsert;

}

当点击左边绿色“+”号按钮后,调用此代理方法: // 提交编辑操作

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"提交编辑操作");

    if (editingStyle == UITableViewCellEditingStyleInsert) {

        switch (indexPath.section) {

            case 0:

                [self.digitalArr insertObject:@"我是新插入的数字" atIndex:indexPath.row];

                break;

            case 1:

                [self.letterArr insertObject:@"我是新插入的字母" atIndex:indexPath.row];

                break;

            default:

                break;

        }

        // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

        [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    }

}


2. 删除

与添加类似,假如我们设置_isDelete = YES,那么代理返回的是UITableViewCellEditingStyleDelete类型,这时删除是这样子的:

你也不喜欢这种做法对不对?那我们换个做法,直接左滑删除某个cell或者点编辑多选/全选然后批量删除cell。


滑动删除

其实,只要你返回UITableViewCellEditingStyleDelete类型,并实现代理方法tableView : commitEditingStyle: forRowAtIndexPath:,然后就可以向左滑动调出删除按钮了。但是这样一来点击添加按钮就不能调出绿色“+”号按钮了,要解决这个问题,需要修改之前的返回类型的代理方法:

// 返回操作类型(添加/删除)

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (!tableView.isEditing) {

        return UITableViewCellEditingStyleDelete;

    }

    return UITableViewCellEditingStyleInsert;

}

// 提交编辑操作

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"提交编辑操作");

    if (editingStyle == UITableViewCellEditingStyleInsert) {

        switch (indexPath.section) {

            case 0:

                [self.digitalArr insertObject:@"我是新插入的数字" atIndex:indexPath.row];

                break;

            case 1:

                [self.letterArr insertObject:@"我是新插入的字母" atIndex:indexPath.row];

                break;

            default:

                break;

        }

        // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

        [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    }else if (editingStyle == UITableViewCellEditingStyleDelete) {

        switch (indexPath.section) {

            case 0:

                if (indexPath.row < self.digitalArr.count) {

                    [self.digitalArr removeObjectAtIndex:indexPath.row];

                }

                break;

            case 1:

                if (indexPath.row < self.letterArr.count) {

                    [self.letterArr removeObjectAtIndex:indexPath.row];

                }

                break;

            default:

                break;

        }

        // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    }

}


批量删除

#define    TABLE_WIDTH      [UIScreen mainScreen].bounds.size.width

#define    TABLE_HEIGHT    [UIScreen mainScreen].bounds.size.height

#import "ViewController.h"

@interface ViewController () {

    BOOL    _isDelete;      // 用于区别是添加还是删除操作

    NSMutableArray *_deleteArr;    // 用于储存将要删除的cell的indexPath

}

@property (weak, nonatomic) IBOutlet UIButton *editBtn;

@property (weak, nonatomic) IBOutlet UIButton *addBtn;

@property (weak, nonatomic) IBOutlet UIView *bottomView;

@property (weak, nonatomic) IBOutlet UIButton *allBtn;

@property (weak, nonatomic) IBOutlet UIButton *deleteBtn;

@property (nonatomic, strong) UITableView *tableView;

@property (nonatomic, strong, nullable) NSMutableArray *digitalArr;

@property (nonatomic, strong, nullable) NSMutableArray *letterArr;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    _isDelete = YES;    // 编辑类型:删除

    self.bottomView.hidden = YES;      //隐藏底部view

    self.deleteBtn.hidden = YES;        //隐藏删除按钮

    // 装载数据源

    self.digitalArr = [@[@"0", @"1", @"2"] mutableCopy];

    self.letterArr  = [@[@"A", @"B", @"C"] mutableCopy];

    // 添加tableView到self.view

    [self.view addSubview:self.tableView];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

}

#pragma mark - UITableViewDelegate

// cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return 60;

}

// Header高度

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {

    return 30;

}

// Footer高度

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    return 30;

}

// 选中了某个cell

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // 判断是否是多选操作

    if (self.tableView.editing) {

        if (_deleteArr == nil) {

            _deleteArr = [NSMutableArray new];

        }

        // 将选中cell的indexPath添加到删除数组deleteArr

        [_deleteArr addObject:indexPath];

        // 显示删除按钮

        self.deleteBtn.hidden = NO;

        return;

    }

}

// 取消选中时 将存放在deleteArr中的数据移除

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {

    // 判断是否是多选操作

    if (self.tableView.editing) {

        //将取消选中的cell的indexPath从数组deleteArr中移除

        [_deleteArr removeObject:indexPath];

        //隐藏删除按钮

        if ([_deleteArr count] == 0) {

            _deleteBtn.hidden = YES;

        }

    }

}

// 返回操作类型(添加/删除)

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"返回操作类型");

    if (!tableView.isEditing) {

        return UITableViewCellEditingStyleDelete;

    }

    return UITableViewCellEditingStyleInsert;

}

// 提交编辑操作

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"提交编辑操作");

    if (editingStyle == UITableViewCellEditingStyleInsert) {

        switch (indexPath.section) {

            case 0:

                [self.digitalArr insertObject:@"我是新插入的数字" atIndex:indexPath.row];

                break;

            case 1:

                [self.letterArr insertObject:@"我是新插入的字母" atIndex:indexPath.row];

                break;

            default:

                break;

        }

        // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

        [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    }else if (editingStyle == UITableViewCellEditingStyleDelete) {

        switch (indexPath.section) {

            case 0:

                if (indexPath.row < self.digitalArr.count) {

                    [self.digitalArr removeObjectAtIndex:indexPath.row];

                }

                break;

            case 1:

                if (indexPath.row < self.letterArr.count) {

                    [self.letterArr removeObjectAtIndex:indexPath.row];

                }

                break;

            default:

                break;

        }

        // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    }

}

#pragma mark - UITableViewDataSource

// Section数量

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 2;

}


// 对应Section中cell的个数

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return self.digitalArr.count;

            break;

        case 1:    // 字母组

            return self.letterArr.count;

            break;

        default:

            break;

    }

    return 0;

}

// Header标题

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return @"数字组头";

            break;

        case 1:    // 字母组

            return @"字母组头";

            break;

        default:

            break;

    }

    return nil;

}

// Footer标题

- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {

    switch (section) {

        case 0:    // 数字组

            return @"数字组尾";

            break;

        case 1:    // 字母组

            return @"字母组尾";

            break;

        default:

            break;

    }

    return nil;

}

// cell

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // 实例化一个UITableViewCell

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

    // 由于已经注册过重用cell,所以这里不必判断是否存在

//    if (cell == nil) {

//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];

//    }

    // 设置cell相关属性

    switch (indexPath.section) {

        case 0:    // 数字组

            if (indexPath.row < self.digitalArr.count) {

                cell.textLabel.text = self.digitalArr[indexPath.row];

            }

            break;

        case 1:    // 字母组

            if (indexPath.row < self.letterArr.count) {

                cell.textLabel.text = self.letterArr[indexPath.row];

            }

            break;

        default:

            break;

    }

    // 返回cell

    return cell;

}

#pragma mark - UI事件

- (IBAction)btnEdit:(UIButton *)sender {

    // 如果当前有别人的编辑操作,取消别人的编辑操作,并退出

    if (self.tableView.isEditing && !sender.selected) {

        // 启动编辑(参数一:tableView是否正在编辑;参数二:是否动画)

        [self.tableView setEditing:!self.tableView.isEditing animated:YES];

        return;

    }

    // 编辑时显示底部view、不显示添加按钮

    sender.selected = !sender.selected;

    if (sender.selected) {

        self.addBtn.hidden = YES;

        self.deleteBtn.hidden = YES;

        self.deleteBtn.selected = NO;

        self.allBtn.selected = NO;

        self.bottomView.hidden = NO;

    }else {

        // 将要隐藏底部view时,还原各种btn

        self.addBtn.hidden = NO;

        self.deleteBtn.hidden = YES;

        self.deleteBtn.selected = NO;

        self.allBtn.selected = NO;

        self.bottomView.hidden = YES;

    }

    // 支持同时选中多行

    self.tableView.allowsMultipleSelectionDuringEditing = YES;

    // 启动编辑(参数一:tableView是否正在编辑;参数二:是否动画)

    [self.tableView setEditing:!self.tableView.isEditing animated:YES];

}

- (IBAction)btnAdd:(UIButton *)sender {

    // 如果当前有别人的编辑操作,取消别人的编辑操作,并退出

    if (self.tableView.isEditing && !sender.selected) {

        // 启动编辑(参数一:tableView是否正在编辑;参数二:是否动画)

        [self.tableView setEditing:!self.tableView.isEditing animated:YES];

        return;

    }

    // 编辑时显示底部view、不显示添加按钮

    sender.selected = !sender.selected;

    if (sender.selected) {

        self.editBtn.hidden = YES;

    }else {

        self.editBtn.hidden = NO;

    }

    _isDelete = NO;    // 编辑类型:添加

    // 取消支持同时选中多行

    self.tableView.allowsMultipleSelectionDuringEditing = NO;

    // 启动编辑(参数一:tableView是否正在编辑;参数二:是否动画)

    [self.tableView setEditing:!self.tableView.isEditing animated:YES];

}

- (IBAction)btnAll:(UIButton *)sender {

    sender.selected = !sender.selected;

    if (sender.selected) {

        // 遍历选中数字cell

        for (int i=0; i

            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

            // 选中TableView中的cell

            [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];

            // 将选中的cell的indexPath存入数组deleteArr

            if (_deleteArr == nil) {

                _deleteArr = [NSMutableArray new];

            }

            [_deleteArr addObject:indexPath];

        }

        // 遍历选中字母cell

        for (int i=0; i

            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:1];

            // 选中TableView中的cell

            [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];

            // 将选中的cell的indexPath存入数组deleteArr

            if (_deleteArr == nil) {

                _deleteArr = [NSMutableArray new];

            }

            [_deleteArr addObject:indexPath];

        }

        // 显示删除按钮

        self.deleteBtn.hidden = NO;

    }else {

        // 遍历取消选中数字cell

        for (int i=0; i

            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

            //取消选中TableView中的cell

            [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

        }

        // 遍历取消选中字母cell

        for (int i=0; i

            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:1];

            //取消选中TableView中的cell

            [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

        }

        // 移除数组deleteArr中所有元素(indexPath)

        if (_deleteArr) {

            [_deleteArr removeAllObjects];

        }

        //隐藏删除按钮

        self.deleteBtn.hidden = YES;

    }

}

- (IBAction)btnDelete:(UIButton *)sender {

    if (self.tableView.isEditing && _deleteArr) {

        // 此处运用i--是为了防止removeObjectAtIndex出错

        for (NSInteger i=_deleteArr.count-1; i>=0; i--) {

            NSIndexPath *indexPath = _deleteArr[i];

            // 数据源同步删除

            switch (indexPath.section) {

                case 0:    // 数字

                    if (indexPath.row < self.digitalArr.count) {

                        [self.digitalArr removeObjectAtIndex:indexPath.row];

                    }

                    break;

                case 1:    // 字母

                    if (indexPath.row < self.letterArr.count) {

                        [self.letterArr removeObjectAtIndex:indexPath.row];

                    }

                    break;

                default:

                    break;

            }

            // 与reloadData不同,此方法带动画效果.(参数二为动画类型)

            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

        }

        [_deleteArr removeAllObjects];

    }

}

#pragma mark - 懒加载

- (UITableView *)tableView {

    if (_tableView == nil) {

        // 实例化一个UITableView

        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, TABLE_WIDTH, TABLE_HEIGHT-64-46)

                                                  style:UITableViewStylePlain];

        // 注册一个cell

        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"myCell"];

        // 设置代理

        _tableView.delegate = self;

        _tableView.dataSource = self;

    }

    return _tableView;

}

@end


3. 排序

和增加、删除相似,要实现排序功能只需实现下面这个协议即可:

/**

移动cell

@param tableView 正在操作的tableView对象

@param sourceIndexPath 移动前的indexPath

@param destinationIndexPath 移动后的indexPath

*/

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {

    // 需要改变数据源的排序

}


四、几种方法创建cell

常用cell的创建方法有两种,一种是使用系统cell,另一种是自定义cell。其中自定义cell又可以分为三种:纯代码创建cell,XIB创建cellstoryboard创建cell


1. 使用系统cell

其实我们上面例子中使用的就是系统cell:通过注册一个UITableViewCell,然后在tableView: cellForRowAtIndexPath:方法里返回一个已经注册到重用队列里的UITableViewCell。

// 注册一个cell

[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"myCell"];

// 在tableView: cellForRowAtIndexPath:方法里实例化一个UITableViewCell,并返回

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

return cell;


2. 自定义cell之纯代码

首先,我们先新建一个继承自UITableViewCell的类MyTableViewCell: 然后导入头文件#import “MyTableViewCell.h”,接下来将上面的系统cell改为我们新建的自定义cell就好了:

// 注册一个cell

[_tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:@"myCell"];

// 在tableView: cellForRowAtIndexPath:方法里实例化一个MyTableViewCell,并返回

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

return cell;


我们可以重写一下cell,来验证是否是使用自定义cell。因为cell继承自UIView,因此我们可以加入如下方法:

- (void)drawRect:(CGRect)rect {

    self.backgroundColor = [UIColor redColor];

}


3. 自定义cell之XIB

和纯代码创建类似,只需要在创建的时候勾选创建XIB文件:

然后我们就会看到XIB里面cell已经自动关联到类MyXibTableViewCell了:

当然,如果我们创建的时候不勾选Also create XIB file选项,也是可以后续单独创建XIB的,只是创建好的XIB要手动关联到我们自定义cell的类名。

接下来,我们为XIB的cell起一个标识符:

最后,我们在注册cell的时候,使用这个标识符找到XIB中的cell,从而创建使用。

// 注册一个cell

[_tableView registerNib:[UINib nibWithNibName:@"MyXibTableViewCell" bundle:nil] forCellReuseIdentifier:@"MyXibTableViewCell"];


在tableView: cellForRowAtIndexPath:方法里实例化一个MyXibTableViewCell,并返回:

// 返回MyXibTableViewCell

- (MyXibTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // 实例化一个MyXibTableViewCell

    MyXibTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyXibTableViewCell"];

    // 设置cell相关属性


    // 返回cell

    return cell;

}

为了验证是否使用XIB的cell,设置cell的背景颜色:


4. 自定义cell之storyboard

先在Main.storyboard里面创建一个tableview和一个cell:

设置tableview的dalegate和datasource:

设置类别:

设置id:

最后,我们可以省掉注册cell这一步(因为系统会自动帮我们注册),直接在tableView: cellForRowAtIndexPath:方法里实返回MyStoryboardTableViewCell

// cell

- (MyStoryboardTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // 实例化一个MyStoryboardTableViewCell

    MyStoryboardTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyStoryboardTableViewCell"];

    // 设置cell相关属性

    if (indexPath.row < self.digitalArr.count) {

        cell.textLabel.text = self.digitalArr[indexPath.row];

    }

    // 返回cell

    return cell;

}

设置storyboard里cell的背景颜色:


五、自定义Header/Footer

如同自定义cell,上面的代码中返回cell的时候返回我们自己创建的cell就好了。对于Header/Footer也一样,我们首先要分别实现两个代理方法:一个返回高度一个返回内容(UIView类型)。


// Header高度

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {

    return 100;

}

// Footer高度

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    return 30;

}

// 自定义Header

- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TABLE_WIDTH, 100)];

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:view.bounds];

    imageView.image = [UIImage imageNamed:@"mas091"];

    [view addSubview:imageView];

    return view;

}

// 自定义Footer

- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TABLE_WIDTH, 30)];

    view.backgroundColor = [UIColor blackColor];

    return view;

}

           

       

 




   

         



你可能感兴趣的:(iOS开发之UI篇(5)—— UITableView)