UITableView 及UITableViewCell 简述

做为在开发中最经常使用的一个控件,UITableView也是在整个UIKit中比较复杂的一个,咱们须要记的东西也特别多.另外苹果官方为咱们提供了UITableViewController这个类,可是在这里咱们不使用它.而是在UIViewController上面添加一个UITableView.数组

UITableView

UITableView继承于UIScrollView,当须要展现的数据量不少的时候,它是能够滚动显示的.bash

UITableView

表视图的每一行都是由单元格(UITableViewCell)表示的.当咱们要对数据分组显示时,苹果为咱们提供了两种基本样式的显示,一种是分组样式,一种则为简单样式.ide

样式

建立UITableView

咱们初始化一个UITableView,并指定样式,而后进行其相关属性的设置,最后将他添加到控制器上.动画

// 1.建立tableView(表视图)并初始化,初始化的时候给一个样式
    UITableView *tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
    
    // 2.设置属性
    // 设置分割线的颜色
    tableView.separatorColor = [UIColor redColor];
    // 设置分割线的风格
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
    // 设置行高
    tableView.rowHeight = 100;
    
    // 设置tableView的tableHeaderView
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 414, 200)];
    headerView.backgroundColor = [UIColor cyanColor];
    tableView.tableHeaderView = headerView;
    
    // 设置tableView的tableFooterView(取消下面多余的线)
    UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
    footerView.backgroundColor = [UIColor magentaColor];
    tableView.tableFooterView = footerView;
    
    // 设置索引条
    
    tableView.sectionIndexColor = [UIColor blackColor];
    // 背景颜色
    tableView.sectionIndexBackgroundColor = [UIColor clearColor];
    //
    tableView.sectionIndexTrackingBackgroundColor = [UIColor lightGrayColor];
    
    
    // 3.添加到视图
    [self.view addSubview:tableView];
    
复制代码

在上面的代码中,咱们对UITableView的分割线和行高,一块儿头尾视图,索引条这几个属性进行了相关设置,对于其余的属性,读者能够本身根据兴趣尝试设置.ui

关于UITableViewCell的相关

在UITableView中用于展现数据的主要就是UITableViewCell.在这里首相我想先说一下关于UITableViewCell的重用.spa

UITableViewCell的重用

若是咱们想利用UITableView展现几条数据的话,咱们能够依次建立这些数量的行来展现这些数据,可是咱们若是有10000行甚至更多的数据要用来向用户展现呢?若是反复建立是十分消耗内存的.代理

这样咱们就天然的想到,为何要建立这么屡次cell呢?咱们为何不将建立好的cell保存起来,放在一个队列中重用呢?这就是UITableViewCell的重用机制.当咱们有10000条数据须要展现的时候,咱们使用这个机制建立的行可能仅须要10个,这样就大大节约了内存.code

UITableViewCell的建立

咱们能够从官方的API中看到UITableViewCell的初始化方法.cdn

![UITableViewCell的初始化方法]://upload-images.jianshu.io/upload_images/1230517-db6401da06482690.png)对象

在建立Cell的时候一样须要指定一个样式,而且设置一个标识.关于样式苹果给定了四个样式

Cell样式

读者能够一一试验,着这里就不作详细的讲解.

if (!cell) {
        // 若重用池里面没有,则去建立identifier标识符的cell
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
    }
复制代码

实际上,上述的建立UITableViewCell的方法是在iOS6以前的老方法.

在iOS6以后咱们只须要注册在重用池中注册一下cell的重用标识符.在注册cell以前咱们必须为cell设置重用标识符,这个标识符必须惟一.咱们一般声明为静态字符串,咱们不须要管理字符串的内存,也不须要对其进行释放.

// 声明重用标识符
static NSString *identifier = @"cellReuse";
复制代码
// 注册(iOS6 以后的写法)
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier];
复制代码

而后在UITableViewDataSource数据源方法中建立就能够了

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    // 先去重用池里面取带有identifier重用标识符的cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];    
    return cell;
}
复制代码

NSIndexPath

NSIndexPath表明UITableView的索引.因为咱们建立的cell是重用的,这样一来咱们便无法精确的肯定这个行.出于此,系统为咱们提供了一个标示行的类,就是NSIndexPath

NSIndexPath的经常使用属性有:

row表示分区中的行的索引,section标示分区的索引.经过这两个属性咱们就能够找到想要的行.

关于自定义cell

关于UITableViewCell咱们是能够根据本身的须要自定义的,咱们只须要从新建立一个类继承自UITableViewCell,在其中设置成须要的样式.而后在注册和建立的时候使用自定义的cell就能够了,在这里咱们假设咱们建立一个MyTableViewCell,而且设置了重用标识符,那么注册和建立的方式以下.

注册
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:identifier];
复制代码
建立
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
复制代码

UITableViewDelegate和UITableViewDataSource

上面是对UITableView的总体结构介绍,若是咱们要建立表视图展现数据,咱们必需要为表视图设置代理和数据源,也就是UITableViewDelegate和UITableViewDataSource

先看数据源代理,数据源顾名思义,就是为表视图提供相关的数据.

数据源中必须实现的方法

咱们看到API中有两个必需要实现的方法

//分区的个数,也就设置这个表分红几组(section)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

//建立或者重用cell的代理方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码

另外咱们能够对其每一个分区的行数(row)进行设置,还能够设置其头尾(titleForHeaderInSection和titleForFooterInSection).

相对这些我跟想跟你们交流的是一些有趣的方法

编辑UITableView

使页面处于可编辑状态

// 第一步: 使页面处于可编辑状态
- (void)edit:(UINavigationController *)sender{
    
    // 设置当前页面能够被编辑
    // 当点击编辑的时候,页面应该处于可编辑状态,而且按钮文字变成"完成"
    if ([sender.title isEqualToString:@"编辑"]) {
        sender.title = @"完成";
        [_tableView setEditing:YES animated:YES];
        
    }else{
        // 当点击完成时,应该让当前页面处于不可编辑状态,而且按钮文字显示为"编辑"
        sender.title = @"编辑";
        [_tableView setEditing:NO animated:YES];
        
    }
    
}
复制代码

指定哪些行能够被编辑

// 指定哪些行能够被编辑
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    
    if (indexPath.section == 2) {
        return NO;
    }
    
        return YES;
    
}
复制代码

根据路径指定编辑的样式

// 根据路径指定编辑的样式
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section == 5) {
        return UITableViewCellEditingStyleInsert;
    }
        return UITableViewCellEditingStyleDelete;
}
复制代码

根据编辑风格完成编辑(先操做数据,在更新UI)

// 根据编辑风格完成编辑(先操做数据,在更新UI)
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    // 删除
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        
        // 找到对应得分组
        NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
        // 当当前分组只有一我的的时候,删除元素以后,对应的分组也应该被删掉
        if (array.count == 1) {
            // 删除大字典里面的该分组
            [_dataDictionary removeObjectForKey:_dataArray[indexPath.section]];
            // 删除掉数组里面对应的key
            [_dataArray removeObjectAtIndex:indexPath.section];
            // 删除UI
            NSIndexSet *set = [NSIndexSet indexSetWithIndex:indexPath.section];
            
            [tableView deleteSections:set withRowAnimation:UITableViewRowAnimationFade];
            
            
        }else{
            
            // 删除数据
            [array removeObjectAtIndex:indexPath.row];
            // 删除对应的cell  更新UI
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
            

        }
        
    }else{
        // 增长
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"悟空",@"name",@"男",@"age",@"八戒",@"hobby",@"18833336666",@"phoneNumber",12,@"age",@"八戒.png",@"picture", nil];
        // 找到对应的分组
        NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
        // 添加元素
        [array insertObject:dic atIndex:indexPath.row+1];
        // 增长 更新UI
        // <1 定义一个新路径
        NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
        [_tableView insertRowsAtIndexPaths:@[newPath] withRowAnimation:UITableViewRowAnimationTop];
    }
    
}
复制代码

移动UITableViewCell

使页面处于可编辑状态

// 第一步 使页面处于可编辑状态
-(void)setEditing:(BOOL)editing animated:(BOOL)animated{
    
    [super setEditing:editing animated:animated];
    
    [_tableView setEditing:editing animated:animated];
    
    self.navigationItem.rightBarButtonItem.title = editing? @"完成":@"编辑";
}
复制代码

指定tableView哪些行能够被移动

// 第二步 指定tableView哪些行能够被移动
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
}
复制代码

移动完成

// 第三步 移动完成
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
    // 获取移动的数据
    NSMutableArray *array = _dataDictionary[_dataArray[sourceIndexPath.section]];
    // 获取移动的对象
    NSDictionary *dic = [array objectAtIndex:sourceIndexPath.row];
    // 先删除
    [array removeObjectAtIndex:sourceIndexPath.row];
    // 再添加
    [array insertObject:dic atIndex:destinationIndexPath.row];
}
复制代码

检测跨区移动

// 检测跨区移动
-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath{
    // 若是就在一个分区,则容许任意移动
    if (sourceIndexPath.section == proposedDestinationIndexPath.section) {
        return proposedDestinationIndexPath;
    }
    // 不然原路滚回去
    return sourceIndexPath;
}
复制代码

经常使用的方法还有

// 快速索引
- (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
复制代码

UITableViewDelegate中经常使用方法

// 设置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码
// 设置分区的header高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
复制代码
// 设置分区的footer高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
复制代码
// 设置分区headerView的视图(设置以后,与titleForHeader方法不共存且设置的高度没有用,想要肯定,headerView的高度,必须重写heightForHeaderInSection方法)
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
复制代码
// 设置分区footerView的视图
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
复制代码
// 点击触发事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码

刷新UITableView

试想一下,当咱们建立UITableView完成以后,咱们向其中添加或者更改删除了一条数据,咱们想让最新的数据呈现出来该怎么办呢?很天然的咱们就想到了从新加载一遍,也就是刷新了.

关于刷新数据系统提供给咱们三种方法.

// 刷新整个表格
-(void)reloadData;
复制代码
// 刷新某些section,animation表示刷新时使用的动画
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
复制代码
// 刷新某些row
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
复制代码

UITableViewController

上面说了这么多,咱们发现建立一个表视图真的好麻烦,要设置代理和数据源,还有那么多的方法.那么有没有一种更好的方法来替代这些方法呢?答案固然是确定的.为了提升开发效率,Apple将UITableView和UIViewController结合,产生了UITableViewController.

使用UITableViewController,咱们只须要根据须要使用其方法进行配置就行了.若是搞懂了UITableView,那么使用UITableViewController就驾轻就熟了,其实这两个一模一样,在此就不赘述了.

总结

以上就是UITableView和UITableViewCell的简单介绍,若是有疑问或者错误,欢迎指正交流,我将不胜感激.转载请保留连接.

相关文章
相关标签/搜索