你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
实现列表二级展开/收起/选择
立即下载
用AI写一个
金额:
2
元
支付方式:
友情提醒:源码购买后不支持退换货
立即支付
我要免费下载
发布时间:2018-04-17
3人
|
浏览:3203次
|
收藏
|
分享
技术:Objective-C
运行环境:Xcode
概述
类似于QQ好友可以展开及收起并且增加编辑时可以进行选择处理的功能。
详细
> 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 # 1、先看效果图  # 2、实现原理 1)通过对`UITableView`进行分组来实现展开收起的功能; 2)通过cell的model和组model中的是否选中和是否展开的标记字段来记录并实现展开/收起/选择的功能; # 3、代码实现 1)创建cell的model类并添加如下属性: ```objective-c // 标记是否选中 @property (nonatomic, assign) BOOL isSelect; // 文字 @property (nonatomic, copy) NSString * title; ``` 其中`isSelect`为必要属性,主要用来标记该cell是否为选中状态。 2)创建组的model类并添加如下属性: ```objective-c // 标记是否展开 @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`属性进行初始化如下: ```objective-c - (instancetype)init { self = [super init]; if (self) { _dataArr = [NSMutableArray new]; } return self; } ``` 这里对`dataArr`进行初始化是为了避免在后边使用的时候因为忘记而导致数据存储不上。 4)对cell进行简单的布局和逻辑处理: ```objective-c #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的方法中通过`model`和`isEditing`两个参数来对cell进行相应的布局和更改。其中参数`isEditing`为该cell是否在编辑状态的标记。 5)对SectionHeaderView进行简单的布局和逻辑处理: ```objective-c #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中实现布局及逻辑处理: ```objective-c #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]; } ``` 首先这里简单模拟加载数据。 ```objective-c #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`判断可以去掉即可。 ```objective-c #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进行相应的修改。
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
1
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
Abner_G
1
例子数量
3
帮助
1
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
实现列表二级展开/收起/选择