美文网首页UI界面处理ios积累
一个简单的可展开和收缩的tableview

一个简单的可展开和收缩的tableview

作者: __夏至未至 | 来源:发表于2016-04-14 14:31 被阅读3240次

    ![Uploading Extand tableView_547722.gif . . .]写了好多的tableview,只是把常用的tableview的应用场景给大家介绍下,(__) 嘻嘻……,话不多说,今天介绍的是一个简单的可以展开和收缩的tableview,类似于qq好友类表。

    Extand tableView.gif

    首先,犹豫是简单的demo,我们就自己构造数据。

    for (int i = 0; i < 4; i++) {
        BaseDataModel *model = [[BaseDataModel alloc] init];
        model.isOpen = NO;
        NSString *name = [NSString stringWithFormat:@"Section:%d",i];
        model.name = name;
        NSMutableArray *array = [NSMutableArray arrayWithCapacity:5];
        for (int j = 0; j < 4; j++) {
            NSString *cellName = [NSString stringWithFormat:@"Cell:%d",j];
            [array addObject:cellName];
        }
        model.dataArray = array;
        [self.dataArray addObject:model];
    }
    

    BaseModel是我们的一个model类。OK,当我们的数据构造好了,接下来就是设计我们的tableview里的section-headerview,主要是给headerview添加一个点击事件,之后在我们的mainviewcontroller里响应,这边可以有很多种解决方法(可以delegate,也可以block,也可以通知)。我用的是block,相对来说简单点。tap事件代码如下:

    if (_isOpen) {
        [UIView animateWithDuration:0.3 animations:^{
            _imageView.transform = CGAffineTransformRotate(_imageView.transform, -M_PI / 2);
        }];
        self.closeblock(self.section);
    }else{
        [UIView animateWithDuration:0.3 animations:^{
            _imageView.transform = CGAffineTransformRotate(_imageView.transform, M_PI / 2);
        }];
        self.openblock(self.section);
    }
    self.isOpen = !self.isOpen;
    

    回到我们的mainviewcontroller里:

    HeaderView *headerView = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, 40)];
    headerView.nameLabel.text = model.name;
    headerView.section = section;
    
    __weak typeof(self) weakself = self;
    headerView.openblock =^(NSInteger secion){
        [weakself openSection:section];
    };
    headerView.closeblock = ^(NSInteger section){
        [weakself closeSection:section];
    };
    

    展开的方法是:

    BaseDataModel *model = self.dataArray[section];
    model.isOpen = !model.isOpen;
    NSMutableArray *indexArray = [NSMutableArray arrayWithCapacity:10];
    for (int i = 0; i < model.dataArray.count; i++) {
        NSIndexPath *indexpath = [NSIndexPath indexPathForRow:i inSection:section];
        [indexArray addObject:indexpath];
    }
    [self.tableView insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
    

    关闭的方法是:

    BaseDataModel *model = self.dataArray[section];
    model.isOpen = !model.isOpen;
    NSMutableArray *indexArray = [NSMutableArray arrayWithCapacity:10];
    for (int i = 0; i < model.dataArray.count; i++) {
        NSIndexPath *indexpath = [NSIndexPath indexPathForRow:i inSection:section];
        [indexArray addObject:indexpath];
    }
    [self.tableView deleteRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
    

    由于当你删除或者添加数据的时候,对应的datasource也要做出相应的改变,所以在返回numberOfRowsInSection时:

    BaseDataModel *model = self.dataArray[section];
    if (model.isOpen) {
        return model.dataArray.count;
    }else{
        return 0;
    }
    

    因为tableView有自己的重用机制,sectionHeaderView也会被重用,所以如果不设置好数据源多的时候会乱掉,在MVC的设计模式里,用于控制View的状态的是model,于是可以将控制状态的参数写入init初始化里:

    - (instancetype)initWithFrame:(CGRect)frame IsOpen:(BOOL)isOpen {
        if (self = [super initWithFrame:frame]) {
            self.backgroundColor = [UIColor whiteColor];
            [self addSubview:self.nameLabel];
            [self addSubview:self.imageView];
            [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOpen)]];
            self.isOpen = isOpen;
            if (self.isOpen) {
                _imageView.transform = CGAffineTransformRotate(_imageView.transform, M_PI / 2);
            }
        }
        return self;
    }
    

    这样的话,一个简单的展开收缩的tableview就完成了。
    demo地址:https://github.com/ioscick/Extand-TableView

    欢迎各位阅读,希望能帮到各位,如果有不正确的地方也可以一起探讨~ thanks。

    相关文章

      网友评论

      • Aprilx:的确跟我想的一样。哥哥,你就没发现你这个东西有BUG吗?因为你在返回头视图的方法里用了[HeaderView alloc] init],所以创建出来的视图会在头视图移出屏幕的时候被Kill,然后在进来的时候会被重新[HeaderView alloc] init];所以,点击的回调就不能用了~!!!请你把- (void)make_date;方法里面的cell的个数从5改成30,然后滚动一下试试。 :angry: (另提醒:如果你使用注册头视图的方式,会有头视图复用的BUG,出现混乱。)~~~请想想别的方法吧~ :sweat:
        __夏至未至:@Aprilx 你可以再去git下下最新的。应该不会出错什么了.....
        Aprilx:@__夏至未至 加油,期待你完善的作品。 :clap:
        __夏至未至:@Aprilx :joy::joy:好的 当时只是demo 我会把他完善下的!
      • yleson:发现了一个bug 随便展开一个之后 把它往上拽直到消失 重新拉下来之后model.isOpen变为NO 再点section就crash了
        __夏至未至:@个阿烁星 在设置箭头的时候If (self.isOpen) 向下,else 正常。
        yleson:@__夏至未至 恩恩 对 可是箭头还原了请问你是怎么解决?
        __夏至未至:@个阿烁星 对的,因为tableview的section header也会重用,在ViewForHeaderInSection里加上'headerView.isOpen = model.isOpen;'这句话就好了,忘记赋值了
      • xxttw:关闭的时候 返回0行 也是可行的
      • 碎辣条:发现一个Bug 打开所有的区段,上下多拉几次,就crash
        __夏至未至:@不会唱歌呢丶 能告诉我bug是怎么样的么- - 我怎么拉都没有发现bug。。。 :sweat:
        不会唱歌呢丶:attempt to insert row 0 into section 2, but there are only 0 rows in section 2 after the update
        __夏至未至:@碎辣条 :smile::smile:好的 谢谢呢 我会修改的
      • 超_iOS:楼主平常不是先刷新数据源再刷新UI吗?你为何可以直接删UI.另外有个类似的问题希望指教下http://www.jianshu.com/p/2229b3616552
        __夏至未至:@小菜超 使用tableview的delete rows或者insert rows的时候先做cell的删除,再做数据的处理,包括cell点击删除的时候,先是cell的删除,同时去数据源的删除
      • e4d93d6aae84:能在同一个区里面展开闭合么
        __夏至未至:@冰阳life 你可以只刷新你需要更新的那一个row或者section,这tableview都是允许的,当然你也可以relsoaddata。
        e4d93d6aae84:@__夏至未至 展开闭合不是需要刷新么,怎么就只刷新当前要展开的单元格
        __夏至未至:@冰阳life 可以的,同样的道理,主要是用datesource和delete或者insert两个方法去控制
      • 9f94d02340f1:留着以后说不定就要用到呢。
      • 泰好笑勒:当前区个数置0应该就可以了吧?
        __夏至未至:@爱笑的豆豆 在模型里面设置了个bool去判断
        泰好笑勒:@__夏至未至 但是模型的数组还在啊
        __夏至未至:@爱笑的豆豆 当你展开的时候就不行了啊
      • Kimball:90度旋转,学到了,:kissing_heart:
        Kimball:@__夏至未至 :smile::smile:
        __夏至未至:@Kimball 关于动画我也粗略的了解 ,transform的一种动画,后续可以介绍下 欢迎关注哦:stuck_out_tongue:
      • 十一岁的加重:给组加个标记,然后要么返回其固有的个数,要么在标识下,只返回0
        __夏至未至:@十一岁的加重 section里的标识嘛?一般是根据model里的bool值判断的。

      本文标题:一个简单的可展开和收缩的tableview

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