Section、row的个数不定的UITableView实现方式最佳实践

先解释下题目,好比下面这个设置页面,里面的内容会根据用户身份、权限等等看到不一样的可设置内容:3d

  • 好比左边有3个section;右边有4个
  • 左边section[0]中有4个row;右边section[0]中有2个row
  • 左边section[0] row[0]可点击;右边则不可点击
  • 等等

咱们先假设最简单的状况,形成左右两边差别的缘由彻底就是因为一个变量的值的不一样致使,isMyHome,若是为YES,则最终看到左边的效果,若是为NO,则最终看到右边的效果。代理

问题来了,你会如何实现UITableView的各类delegate?code

错误示范,一种很丑的实现方式

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (self.isMyHome) {
        return 3;
    } else {
        return 4;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.isMyHome) { // 有3个section
        switch (section) {
            case 0:
                return 4;
                break;
            case 1:
                return 1;
                break;
            case 2:
                return 2;
                break;
            default:
                break;
        }
    } else {
        switch (section) {
            case 0:
                return 2;
                break;
            case 1:
                return 1;
                break;
            case 2:
                return 1;
                break;
            case 3:
                return 1;
                break;
            default:
                break;
        }
    }
    return 0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.isMyHome) {
        if (indexPath.section == 2 && indexPath.row == 0) { // 有一个row稍微有点高
            return 70;
        } else {
            return 40;
        }
    } else {
        return 40;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = ni;
    // ...真的不想写了快吐了,这才一个变量的区别
    return cell;
}

以上的写法有两个大问题:blog

  1. 任什么时候候都要考虑isMyHome的值,写一堆if、else、switch。(一个row是否要显示,row的index是多少,row长什么样都是变量,都要考虑)
  2. 使用0,1,2,3等数字,没有含义,没有使用枚举,难以维护,增删一行都要改所有,还容易出bug。

这才一个变量啊,试想实际项目中,每每不少变量综合决定了哪一个row显示、那个row不显示、row长什么样。想一想下,若是有一天产品经理说,去掉“宝宝信息”这行,我以为你就要疯了,要把index所有都减一,每一个代理都要检查一遍是否对得上index。ci

因此,这两个问题,致使的后果:难实现、容易出bug、不易维护。产品

最佳实现

既然上面的实现这么很差,该怎么实现呢?其实就是逐一解决上面提到的两个问题。it

对于1,其实形成问题的本质缘由是:在任什么时候候,把一个row应该显示与否、以及长什么样子、row对应的index是什么, 这些问题都融合在一块儿了,将问题复杂程度一下提高了不少。对于2,都使用枚举就行了,避免
这里提出解决办法:io

  1. 固定section的个数、每一个section中row的个数,都取全部条件下,最多的那个值。(numberOfSectionsInTableView、numberOfRowsInSection只控制个数问题)
  2. heightForRowAtIndexPath中控制row的显示与否,若是不显示,只须要高度返回0就行了
  3. cellForRowAtIndexPath里,因为section、row的index都是固定不变的,只须要关心cell的内容就行了。
  4. 使用枚举

这样,“section、row的个数(index)”、“section、row是否显示”、“row长什么样”,这三个问题就分散到了4个delegate中:table

  • numberOfSectionsInTableView、numberOfRowsInSection只解决“section、row的个数(index)”的问题;
  • heightForRowAtIndexPath只解决“section、row是否显示”的问题
  • cellForRowAtIndexPath只解决“row长什么样”的问题

代码长这样:变量

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 4;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    switch (section) {
        case SectionOne:
            return 4;
            break;
        case SectionTwo:
            return 1;
            break;
        case SectionThree:
            return 2;
            break;
        case SectionFour:
            return 1;
            break;
            
        default:
            break;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        switch (indexPath.row) {
            case SectionOneRowOne:
                return 40
                break;
            case SectionOneRowTwo:
                return self.isMyHome ? 40 : 0;
                break;
            case SectionOneRowThree:
                return self.isMyHome ? 40 : 0;
                break;
            case SectionOneRowFour:
                return 40
                break;
                
            default:
                break;
        }
    } else if (indexPath.section == 1) {
        return 40;
    } else if (indexPath.section == 2) {
        switch (indexPath.row) {
            case SectionThreeRowOne:
                return self.isMyHome ? 70 : 0;
                break;
            case SectionThreeRowTwo:
                return 40;
                break;
            default:
                break;
        }
    } else {
        return self.isMyHome ? 0 : 40;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 对于每一个cell,配置内容就行了,index都是固定的
}

若是产品经理说,删除“宝宝信息”这行吧,那么咱们只要把heightForRowAtIndexPath,相应高度改成0就行了,以后产品经理反悔还能够直接改回来,就算想彻底删了,也很省事,不容易出bug。

总结

核心思想,其实就是,UITableView的几个delegate,分别只解决一个问题,不要把问题都揉在一块儿,让代码变得复杂

其余问题

假如要去掉一整个section怎么办,好比产品经理说,不要“我在小家的称呼”这行了。

固然,没问题,咱们直接把heightForRowAtIndexPath里这行,改成0就行了嘛!

等等,虽然这行没了,可是前两个section之间的间隙,有可能会变大,由于只是设置了height为0而已,seciton还在嘛。这种状况怎么办?
不用担忧,只要设置section的间隙,使用相似这种方式去设置,响应的改变section header的值,就行了~
其实,这种设置section的间隙的方式,也是咱们常用的嘛,基本都不太用系统默认的间隙。

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return section == 0 ? 0 : 8;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return [UIView new];
    }
    UIView *sectionHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 8)];
    sectionHeader.backgroundColor = [UIColor clearColor];
    return sectionHeader;
}
相关文章
相关标签/搜索