UITableView的折叠效果

UITableView的折叠效果


  项目需求要做出一级列表的效果,也就是将UITableView模拟出折叠section的效果。网上类似的代码demo还是很多哒~我这里是自己进行一个总结巩固,顺便理清一下思路。

  我写出了两个效果,一个是没有互斥效果的,即当前可展开多个section,一个是有互斥效果的,即当前只会展开一个section,当展开第二个分区的时候第一个分区会有一个自动收起的动作。


  效果图


1.可展开多个分区的GIF

可展开多个section

2.只可以展开一个分区GIF

只展开一个section

1.可展开多个分区的实现

我们需要一个数组来存储当前展开的分区。

    @property (strong, nonatomic) NSMutableArray *currentExpandSection;  //展开的section

通过在返回分区内cell的数量时,判断该cell是否在currentExpandSection数组里,来决定当前cell是否折叠(即返回0行)。

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    NSMutableIndexSet * iset = [NSMutableIndexSet indexSet];
    [iset addIndex:section];
    //判断当前section是否是收起状态的
    if ([self.currentExpandSection containsObject:iset]) {
        return 0;
    } else {
        NSString *key = [self.sectionTitleArray objectAtIndex:section];
        NSArray *array = [self.sourceDic objectForKey:key];
        return array.count;
    }
    }

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section函数里返回了一个UIButton,button的tag就是section的值,点击改变button选中状态,给它一个点击事件,判断选中的状态来决定是收起还是展开,控制currentExpandSection里元素的增减,并刷新分区。

    -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    UIButton * btnSection = [UIButton buttonWithType:UIButtonTypeCustom];
    //刷新分区会刷新按钮,无法保持选中信息,检索后手动赋值为选中
    NSMutableIndexSet * iset = [NSMutableIndexSet indexSet];
    [iset addIndex:section];
    //若当前分区在currentExpandSection中表明它当前被选中且被展开
    if ([self.currentExpandSection containsObject:iset]) {
        btnSection.selected = YES;
    }
    [btnSection setBackgroundColor:[UIColor lightGrayColor]];
    [btnSection setTitle:self.sourceDic.allKeys[section] forState:UIControlStateNormal];
    [btnSection addTarget:self action:@selector(btnSectionClicked:) forControlEvents:UIControlEventTouchDown];
    [btnSection setTag:section];

    return btnSection;
    }

    - (void)btnSectionClicked:(UIButton *)sender {
    UIButton *button = (UIButton *)sender;
    //点击后改变选中的状态,改变后若为选中表示展开,将其对应的分区加入currentExpandSection。
    button.selected = !button.selected;

    //通过button的tag来获得第几个分区
    NSMutableIndexSet * iset = [NSMutableIndexSet indexSet];
    [iset addIndex:button.tag];

    //button点击后被选中就展开
    if (button.isSelected) {
        [self.currentExpandSection addObject:iset];
    }else {
        if ([self.currentExpandSection containsObject:iset]) {
            [self.currentExpandSection removeObject:iset];
        }
    }
    //刷新点击的分区,可选择动画
    [self.tableView reloadSections:iset withRowAnimation:UITableViewRowAnimationAutomatic];
    }

2.只展开一个分区的实现

因为每次点击只会展开一个分区,所以需要知道当前是哪个section被展开。

    @property (assign, nonatomic) NSInteger currentExpandSection;       //当前展开的section

因为一开始所有分区都为收起状态,所以不指向任何一个分区,默认值给-1.

    //模拟数据
    self.sourceDic = [[NSMutableDictionary alloc] init];
    for (int i = 0; i < 10; i ++) {
        NSString * key = [[NSString alloc] initWithFormat:@"key %d",i];
        NSMutableArray *list = [[NSMutableArray alloc] init];
        for (int j = 0; j < i + 1; j ++) {
            NSString *item = [[NSString alloc] initWithFormat:@"%d",j];
            [list addObject:item];
        }
        [self.sourceDic setObject:list forKey:key];
    }
    self.currentExpandSection = -1;
    self.sectionTitleArray = [self.sourceDic allKeys];

在返回分区里的cell数量时,只有当前展开的section返回相应的行数,其余的section都返回0,保证视觉上每次只会展开一个分区。

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    //当前展开的分区返回正确的行数,其余返回0
    if (section == self.currentExpandSection) {
        NSString *key = [self.sectionTitleArray objectAtIndex:section];
        NSArray *array = [self.sourceDic objectForKey:key];
        return array.count;
    }else {
        return 0;
    }
    }

与展开多个分区一样,在-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section函数里返回了一个UIButton,需要判断分区是否是当前的展开分区,

    -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    UIButton * btnSection = [UIButton buttonWithType:UIButtonTypeCustom];
    //刷新分区会刷新按钮,无法保持选中信息,检索后手动赋值
    NSMutableIndexSet * iset = [NSMutableIndexSet indexSet];
    [iset addIndex:section];
    //分区如果是当前的展开分区,选中状态为yes
    if (self.currentExpandSection == section) {
        btnSection.selected = YES;
    }

    [btnSection setBackgroundColor:[UIColor lightGrayColor]];
    [btnSection setTitle:self.sourceDic.allKeys[section] forState:UIControlStateNormal];    
    [btnSection addTarget:self action:@selector(btnSectionClicked:) forControlEvents:UIControlEventTouchDown];
    [btnSection setTag:section];

    return btnSection;
    }

button的点击事件比上面那种情况稍微复杂一丢丢,同样,button的tag就是第几个分区,在currentExpandSection未被赋值为新的点击分区时用一个变量oldsection保存点击之前是第几个分区被展开.

    - (void)btnSectionClicked:(UIButton *)sender {
    UIButton *button = (UIButton *)sender;
    button.selected = !button.selected;
    NSMutableIndexSet * iset = [NSMutableIndexSet indexSet];
    [iset addIndex:button.tag];

    NSInteger oldsection = self.currentExpandSection;
    if (oldsection != -1) { //不等于-1表示当前有分区被展开
        if (oldsection == button.tag){
            //点击前展开的分区与当前点击的分区是同一个分区,要折叠此分区
            //并且currentExpandSection重新赋值-1,表示当前没有分区被展开
            self.currentExpandSection  = -1;
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:oldsection] withRowAnimation:UITableViewRowAnimationAutomatic];
        }else {
            //当前展开分区与被点击展开的分区不同时
            //先把当前展开的分区收起,恢复到没有展开的状态,刷新分区
            self.currentExpandSection  = -1;
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:oldsection] withRowAnimation:UITableViewRowAnimationAutomatic];
            //把点击的分区赋值给currentExpandSection。并刷新分区
            self.currentExpandSection = button.tag;
            [self.tableView reloadSections:iset  withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }else {
        //当前没有分区被展开,直接展开被点击的分区
        self.currentExpandSection = button.tag;
        [self.tableView reloadSections:iset  withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    NSLog(@"%@", iset);
    }

DEMO下载地址:git
PS :博客的注释比DEMO里的注释要详细很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值