美文网首页iOS开发收藏文章技术iOS开发
UITableView 及UITableViewCell 简述

UITableView 及UITableViewCell 简述

作者: 相关函数 | 来源:发表于2016-02-15 15:14 被阅读1068次

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

    First

    UITableView继承于UIScrollView,当需要展示的数据量很多的时候,它是可以滚动显示的.

    UITableView

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

    样式

    创建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的分割线和行高,一起头尾视图,索引条这几个属性进行了相关设置,对于其他的属性,读者可以自己根据兴趣尝试设置.

    关于UITableViewCell的相关

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

    UITableViewCell的重用

    如果我们想利用UITableView展示几条数据的话,我们可以依次创建这些数量的行来展示这些数据,但是我们如果有10000行甚至更多的数据要用来向用户展示呢?如果反复创建是十分消耗内存的.

    这样我们就自然的想到,为什么要创建这么多次cell呢?我们为什么不将创建好的cell保存起来,放在一个队列中重用呢?这就是UITableViewCell的重用机制.当我们有10000条数据需要展示的时候,我们使用这个机制创建的行可能仅需要10个,这样就大大节约了内存.

    UITableViewCell的创建

    我们可以从官方的API中看到UITableViewCell的初始化方法.

    ![UITableViewCell的初始化方法]:https://img.haomeiwen.com/i1230517/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的简单介绍,如果有疑问或者错误,欢迎指正交流,我将不胜感激.转载请保留链接.

    相关文章

      网友评论

      本文标题:UITableView 及UITableViewCell 简述

      本文链接:https://www.haomeiwen.com/subject/zrjpkttx.html