实现列表二级展开/收起/选择

代码地址如下:
http://www.demodashi.com/demo/12628.html

1、先看效果图

2、实现原理

1)通过对UITableView进行分组来实现展开收起的功能;

2)通过cell的model和组model中的是否选中和是否展开的标记字段来记录并实现展开/收起/选择的功能;

3、代码实现

1)创建cell的model类并添加如下属性:

// 标记是否选中
@property (nonatomic, assign) BOOL isSelect;
// 文字
@property (nonatomic, copy) NSString * title;

其中isSelect为必要属性,主要用来标记该cell是否为选中状态。

2)创建组的model类并添加如下属性:

// 标记是否展开
@property (nonatomic, assign) BOOL isShow;
// 标记是否全选
@property (nonatomic, assign) BOOL isAllSelect;
// 存储该组的数据
@property (nonatomic, strong) NSMutableArray * dataArr;
// 组标题
@property (nonatomic, copy) NSString * title;
@end

其中isShow、isAllSelect、dataArr为必要属性,isShow用来标记该组是否为展开状态,isAllSelect用来标记该组是否为全部选中状态,dataArr用来存储该组的数据。

3)需要在组的model类.m文件中重写init方法,对dataArr属性进行初始化如下:

- (instancetype)init {

    self = [super init];

    if (self) {

        _dataArr = [NSMutableArray new];
    }
    return self;
}

这里对dataArr进行初始化是为了避免在后边使用的时候因为忘记而导致数据存储不上。

4)对cell进行简单的布局和逻辑处理:

#pragma mark - config cell

- (void)configCellWithModel:(RHListModel *)model indexPath:(NSIndexPath *)indexPath isEditing:(BOOL)isEditing {

    _lab_title.text = model.title;
    _img_sel.hidden = !isEditing;
    if (isEditing) {

        [_lab_title mas_updateConstraints:^(MASConstraintMaker *make) {

            make.left.mas_equalTo(60);
        }];
        if (model.isSelect) {

//            _img_sel.image = [UIImage imageNamed:@""];
            _img_sel.backgroundColor = Color_Red;
        } else {

//            _img_sel.image = [UIImage imageNamed:@""];
            _img_sel.backgroundColor = Color_Blue;
        }
    } else {

        [_lab_title mas_updateConstraints:^(MASConstraintMaker *make) {

            make.left.mas_equalTo(30);
        }];
    }
}

这里只创建了一个label和一个imageView,其中label用来显示标题,imageView用来显示是否为选中状态。

在该配置cell的方法中通过modelisEditing两个参数来对cell进行相应的布局和更改。其中参数isEditing为该cell是否在编辑状态的标记。

5)对SectionHeaderView进行简单的布局和逻辑处理:

#pragma mark - config section header

- (void)configSectionHeaderWithModel:(RHListSectionModel *)sectionModel isEditing:(BOOL)isEditing tapEventHandler:(void (^)(void))tapHandler selEventHandler:(void (^)(BOOL))selHandler {

    _tapEvent = tapHandler;
    _selEvent = selHandler;
    _lab_title.text = sectionModel.title;
    _btn_sel.selected = sectionModel.isAllSelect;
    _img_sel.hidden = !isEditing;
    _btn_sel.hidden = !isEditing;
    if (isEditing) {

        [_lab_title mas_updateConstraints:^(MASConstraintMaker *make) {

            make.left.mas_equalTo(40);
        }];
        if (sectionModel.isAllSelect) {

//            _img_sel.image = [UIImage imageNamed:@""];
            _img_sel.backgroundColor = Color_Red;
        } else {

//            _img_sel.image = [UIImage imageNamed:@""];
            _img_sel.backgroundColor = Color_Blue;
        }
    } else {

        [_lab_title mas_updateConstraints:^(MASConstraintMaker *make) {

            make.left.mas_equalTo(10);
        }];
    }
    if (sectionModel.isShow) {

//        _img_arrow.image = [UIImage imageNamed:@""];
        _img_arrow.backgroundColor = Color_Yellow;
    } else {

//        _img_arrow.image = [UIImage imageNamed:@""];
        _img_arrow.backgroundColor = Color_Purple;
    }
}
@end

这里通过对headerView添加手势的方式对其添加点击事件,由于需要在外部获取到该点击事件,所以这里使用了block回调的方式来回调点击该组和点击选择按钮的两个事件。其中tapHandler为点击该组时的回调,selHandler为点击选择按钮时的回调。在这里分别定义了两个block属性来接收并在点击事件中进行回调赋值。

这里对标题和选择按钮图片的处理与在cell中的类似,这里不再多说。

6)在VC中实现布局及逻辑处理:

#pragma mark - load data

- (void)loadData {

    for (int i = 0; i < 5; i++) {

        RHListSectionModel * sectionModel = [[RHListSectionModel alloc] init];
        sectionModel.title = [NSString stringWithFormat:@"第%d组", i + 1];
        for (int j = 0; j < arc4random()%5 + 4; j++) {

            RHListModel * model = [[RHListModel alloc] init];
            model.title = [NSString stringWithFormat:@"第%d组,第%d个", i + 1, j + 1];
            [sectionModel.dataArr addObject:model];
        }
        [_dataArr addObject:sectionModel];
    }
    [_tableView reloadData];
}

首先这里简单模拟加载数据。

#pragma mark - btn event

- (void)clickEdit:(UIButton *)sender {

    sender.selected = !sender.selected;
    if (sender.selected) {

        for (RHListSectionModel * sectionModel in self.dataArr) {

            sectionModel.isAllSelect = NO;
            for (RHListModel * model in sectionModel.dataArr) {

                model.isSelect = NO;
            }
        }
    }
    [_tableView reloadData];
}

这是在导航上边添加了一个编辑按钮的点击事件,点击按钮切换按钮的选中状态。通过此来切换列表是否为编辑状态。

这里是在按钮选中前对所有数据的选中状态进行了初始化,即全部设置为未选中。如果有需求需要记住编辑时的状态,这里的if判断可以去掉即可。

#pragma mark - tableView dataSource and delegate

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return self.dataArr.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    RHListSectionModel * sectionModel = self.dataArr[section];
    if (!sectionModel.isShow) {

        return 0;
    }
    return sectionModel.dataArr.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    RHListCell * cell = [tableView dequeueReusableCellWithIdentifier:@"RHListCell" forIndexPath:indexPath];
    RHListSectionModel * sectionModel = self.dataArr[indexPath.section];
    RHListModel * model = sectionModel.dataArr[indexPath.row];
    [cell configCellWithModel:model indexPath:indexPath isEditing:self.btn_edit.selected];
    return cell;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    RHListSectionHeaderView * headerView = [[RHListSectionHeaderView alloc] init];
    RHListSectionModel * sectionModel = self.dataArr[section];
    [headerView configSectionHeaderWithModel:sectionModel isEditing:self.btn_edit.selected tapEventHandler:^{

        sectionModel.isShow = !sectionModel.isShow;
        [tableView reloadData];
    } selEventHandler:^(BOOL isAllSelect) {

        sectionModel.isAllSelect = isAllSelect;
        if (isAllSelect) {

            for (RHListModel * model in sectionModel.dataArr) {

                model.isSelect = YES;
            }
        } else {

            for (RHListModel * model in sectionModel.dataArr) {

                model.isSelect = NO;
            }
        }
        [tableView reloadData];
    }];
    return headerView;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    if (!self.btn_edit.selected) {

        return;
    }
    RHListSectionModel * sectionModel = self.dataArr[indexPath.section];
    RHListModel * model = sectionModel.dataArr[indexPath.row];
    model.isSelect = !model.isSelect;
    if (model.isSelect) {

        int count = 0;
        for (RHListModel * mod in sectionModel.dataArr) {

            if (mod.isSelect) {

                count++;
            }
        }
        if (count == sectionModel.dataArr.count) {

            sectionModel.isAllSelect = YES;
        }
    } else {

        sectionModel.isAllSelect = NO;
    }
    [tableView reloadData];
}

这里是tableView的主要代理实现方法主要说一下返回SectionHeader及点击cell的两个代理。

其中返回SectionHeader的代理里边使用定制的SectionHeader并调用外漏的配置方法,在block里边进行展开/收起/选中/取消选中该组的处理,最后对tableView进行刷新。

cell的点击事件里边主要是对在点击cell时的处理,如果在编辑状态下,点击cell时需要统计该组中选中cell的个数,来实时改变改组的组的选中状态。

4、项目结构

主要采用MVC的方式来实现

OK!至此所有功能已经实现,我们在使用的时候可以根据自己的需求对model和cell进行相应的修改。实现列表二级展开/收起/选择

代码地址如下:
http://www.demodashi.com/demo/12628.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

原文地址:https://www.cnblogs.com/demodashi/p/9436511.html

时间: 2024-10-03 23:53:29

实现列表二级展开/收起/选择的相关文章

QQ列表的展开收起

RootViewController.h @interface RootViewController : UIViewController<UITableViewDataSource,UITableViewDelegate> { BOOL Close[15]; //用于存放每一组的收起展开状态 YES 是收起 NO是展开 UITableView *_tableView; } @property(nonatomic, retain)NSArray *data; RootViewControlle

实现列表展开收起效果

$(".btn").click(function () {$(this).parents("当前元素最外层div的class").toggleClass("showDiv").siblings().removeClass("showDiv");});css:.最外层div class .需要收起展开的div的class{display: none;}.showDiv .需要收起展开的div的class{display: blo

展开收起播放列表

//播放器关闭展开播放列表  by sunhw    (function() {        function PlayFold( option ) {            this.option = T.object.extend( {                root           : '',                foldBtn        : '',                playListLayout : '',                packu

HTML-003-模拟IDE代码展开收起功能简单示例

当先我们在日常的编程开发工作中使用编程工具(例如 Eclipse.Sublime 等等)都有相应的代码折叠展开功能,如下图所示,极大的方便了我们的编码工作. 同时,我们在日常的网页,尤其的广大的博客网站的源码展示部分,都采用了此种显示方式,如下图所示(示例引用位置:008-Selenium 操作下拉列表实例-Select): 这么做的意义何在呢?我觉得其实际应用有如下两种: 内容的展示和隐藏:将用户最关心.感兴趣的内容展示给用户,若用户想继续深入了解,则可通过点击展示或隐藏按钮达到查看.隐藏内容

Android UI(五)云通讯录项目之联系人列表,带侧滑选择,带搜索框

作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节.交流QQ群:[编程之美 365234583]http://jq.qq.com/?_wv=1027&k=XVfBTo 要捐钱的就打支付宝吧:13958686678(泥瓦匠开个玩笑~) 一.前言 继续AndroidUI系列,泥瓦匠又要开始扯淡了.哈哈今天在文章头加了个支付宝账号.我也真逗,至今没收到一笔是写博客的钱.或是分享的.泥瓦匠也就挂着逗逗乐

Javascript展开收起

<!DOCTYPE html><html><head><meta charset="utf-8" /><title>展开收起</title><style type="text/css">body{ margin: 0 auto; padding: 0px;}#pn{ background: #e8e8e8; width: 600px; height: auto; margin: 0

展开-收起

1.需求,展开-收起 html代码: css中默认pr_list"是隐藏的. 一开始js是这样子写的 出现问题:出现的bug,就是只能点击一次,点第二次就不行了. 分析问题:收起来后,那句 "查看楼盘简介" 是我后来手动插进去的,还没有绑定任何事件,与我前面绑定事件的元素,不是一个东西: 解决问题:

JS+CSS实现可展开/收起的QQ在线客服悬浮代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JS+CSS实现可展开/收起的QQ在线客服

Jquery 展开收起

需求:点击展开显示详细内容,收起后隐藏内容 实现: Index.cshtml 显示 ... ... <tr> <td> <a asp-action="Edit" asp-route-id="@item.Nid" asp-route-lcid="@item.Lcid">编辑</a> | <a asp-action="Delete" asp-route-id="@it