【iOS】UITableView中section的展开和收起

来源:互联网 发布:人工智能行业研究报告 编辑:程序博客网 时间:2024/05/16 04:25

我们在做项目时,经常遇到UITableView需要展开与收起的情况,类似手机QQ的折叠,而且根据数据的不同判断有多少行需要展开与收起.之前做项目的时候也使用过,最近有时间整理,就把之前是怎么操作的记录下来。


首先,我们先说下思路:

思路:在写代码的时候我们可以很容易的写出cell和setion。但是系统并没有提供记录section状态的方法或是属性。我们需要点击某个section的时候收起和弹出cell。怎么做呢?只有是人为的给section增加一个标记了,每个section一个标记,section被点击了就把这个状态标记取反,根据这个标记来展开和收起cell

其中,设置方式又分为两种:

第一种:

设置cell的高度,高度为0了cell就收起了,高度大于0了cell就弹出

下面就直接贴代码了。


ViewController.m

#import "ViewController.h"#import "SectionViewController.h"@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>@property (nonatomic,strong)UITableView *tableView;@property (nonatomic,strong)NSMutableArray *sectionArray;@property (nonatomic,strong)NSMutableArray *flagArray;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    [self makeData];    _tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];    _tableView.delegate = self;    _tableView.dataSource = self;    [self.view addSubview:_tableView];    // Do any additional setup after loading the view, typically from a nib.}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}/** *  处理数据  _sectionArray里面存储数组 */- (void)makeData{    _sectionArray = [NSMutableArray array];    _flagArray  = [NSMutableArray array];    NSInteger num = 6;    for (int i = 0; i < num; i ++) {        NSMutableArray *rowArray = [NSMutableArray array];        for (int j = 0; j < arc4random()%20 + 1; j ++) {            [rowArray addObject:[NSString stringWithFormat:@"%d",j]];        }        [_sectionArray addObject:rowArray];        [_flagArray addObject:@"0"];    }}//设置组数- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return _sectionArray.count;}//设置行数- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    NSArray *arr = _sectionArray[section];    return arr.count;}//组头高度-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{    return 44;}//cell的高度- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    if ([_flagArray[indexPath.section] isEqualToString:@"0"])        return 0;    else        return 44;}//组头- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{    UILabel *sectionLabel = [[UILabel alloc] init];    sectionLabel.frame = CGRectMake(0, 0, self.view.frame.size.width, 444);    sectionLabel.textColor = [UIColor orangeColor];    sectionLabel.text = [NSString stringWithFormat:@"组%d",section];    sectionLabel.textAlignment = NSTextAlignmentCenter;    sectionLabel.tag = 100 + section;    sectionLabel.userInteractionEnabled = YES;    sectionLabel.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"itembg.png"]];        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(sectionClick:)];    [sectionLabel addGestureRecognizer:tap];        return sectionLabel;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString *identify = @"Cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identify];    if (cell == nil) {        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identify];    }    cell.textLabel.text= [NSString stringWithFormat:@"第%d组的第%d个cell",indexPath.section,indexPath.row];    cell.clipsToBounds = YES;//这句话很重要,防止cell覆盖显示    return cell;}- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    SectionViewController *sVC = [[SectionViewController alloc] init];    sVC.rowLabelText = [NSString stringWithFormat:@"第%d组的第%d个cell",indexPath.section,indexPath.row];    [self presentViewController:sVC animated:YES completion:nil];}- (void)sectionClick:(UITapGestureRecognizer *)tap{    int index = tap.view.tag % 100;        NSMutableArray *indexArray = [[NSMutableArray alloc]init];    NSArray *arr = _sectionArray[index];    for (int i = 0; i < arr.count; i ++) {        NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:index];        [indexArray addObject:path];    }    //展开    if ([_flagArray[index] isEqualToString:@"0"]) {        _flagArray[index] = @"1";        [_tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationBottom];  //使用下面注释的方法就 注释掉这一句    } else { //收起        _flagArray[index] = @"0";        [_tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationTop]; //使用下面注释的方法就 注释掉这一句    }    //另一种刷新方式    //  NSRange range = NSMakeRange(index, 1);    //  NSIndexSet *sectionToReload = [NSIndexSet indexSetWithIndexesInRange:range];    //  [_tableView reloadSections:sectionToReload withRowAnimation:UITableViewRowAnimationAutomatic];}@end

附上代码的下载地址:Demo地址




第二种:

设置section数组的个数,数组个数为0了cell就收起了,数组个数大于0了cell就弹出

demo:

附上主要代码片段,仅提供思路参考:


1.设置数据源:


//设置属性@property(nonatomic, strong) NSMutableArray* listArray;/**< 数组 */@property(nonatomic, strong) NSMutableDictionary* foldInfoDic;/**< 存储开关字典 */@property(nonatomic, strong) NSDictionary *topDic;@property(nonatomic, strong) NSDictionary *orderDic;@property(nonatomic, strong) NSDictionary *userDic;@property(nonatomic, strong) NSDictionary *accountDic;@property(nonatomic, strong) NSDictionary *paymentDic;@property(nonatomic, strong) NSDictionary *bootomDic;#pragma marl ---load lazing-(NSDictionary *)topDic{    if (!_topDic) {        _topDic = @{@"title":@"",@"data":@[@""]};    }    return _topDic;    }-(NSDictionary *)orderDic{    if (!_orderDic) {        _orderDic = @{@"title":@"订单信息",@"data":@[@"订单信息",@"收益",@"交易类型",@"支付币种",@"汇率",@"备注"]};    }    return _orderDic;    }-(NSDictionary *)userDic{    if (!_userDic) {        _userDic = @{@"title":@"用户信息",@"data":@[@"用户名",@"联系方式"]};    }    return _userDic;}-(NSDictionary *)accountDic{    if (!_accountDic) {        _accountDic = @{@"title":@"收款账户信息",@"data":@[@"联系方式",@"开户银行",@"开户名"]};    }    return _accountDic;}-(NSDictionary *)paymentDic{        if (!_paymentDic) {        _paymentDic = @{@"title":@"汇款凭证",@"data":@[@""]};    }    return _paymentDic;}-(NSDictionary *)bootomDic{    if (!_bootomDic) {        _bootomDic = @{@"title":@"",@"data":@[@"订单编号",@"下单时间"]};    }    return _bootomDic;    }-(NSMutableArray *)listArray{    if (!_listArray) {        _listArray = [NSMutableArray array];    }    return _listArray;    }-(NSMutableDictionary *)foldInfoDic{    if (!_foldInfoDic) {        _foldInfoDic = [NSMutableDictionary dictionary];    }    return _foldInfoDic;    }

2.根据需要加载需要的数据源,并设置记录是否展开的section对应de字典

    [self.listArray addObject:self.topDic];    [self.listArray addObject:self.orderDic];    [self.listArray addObject:self.userDic];    [self.listArray addObject:self.accountDic];    //根据项目需要判断需要添加哪些section数据    if (self.orderType == FinancierAcceptarbitrateType || self.orderType == FinancierAcceptFinishType) {        [self.listArray addObject:self.paymentDic];    }else{        if (self.orderType == FinancierAcceptTradingType) {                    }    }        [self.listArray addObject:self.bootomDic];    //设置section属性    for (int i=0; i<self.listArray.count; i++) {        NSDictionary *dic = self.listArray[i];        NSString *key = [NSString stringWithFormat:@"%d",i];        [self.foldInfoDic setObject:@"1" forKey:key];    }    

设置tableView:

#pragma mark --- UITableViewDataSource and UITableViewDelegate Methods-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{        return self.listArray.count;}-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{        NSDictionary *dic = self.listArray[section];    NSArray *cellArray = [NSArray arrayWithArray:dic[@"data"]];        NSString *key = [NSString stringWithFormat:@"%d",(int)section];    BOOL folded = [[self.foldInfoDic objectForKey:key] boolValue];    if (folded) {        return cellArray.count;    }else{        return 0;    }}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{        if (indexPath.section == 0 ) {        static NSString *CellIdentifier = @"FinancierAcceptDetailTopCell";        FinancierAcceptDetailTopCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];        if (cell == nil) {            cell = [[FinancierAcceptDetailTopCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];            cell.selectionStyle = UITableViewCellSelectionStyleNone;        }        cell.orderType = self.orderType;                //                cell.delegate = self;        cell.layer.masksToBounds = YES;                return cell;    }else{        static NSString *CellIdentifier = @"Cell";        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];        if (cell == nil) {            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];            cell.selectionStyle = UITableViewCellSelectionStyleNone;            cell.textLabel.textColor = [UIColor grayColor];            cell.textLabel.font = [UIFont systemFontOfSize:15];            cell.detailTextLabel.textColor = [UIColor blackColor];            cell.detailTextLabel.font = [UIFont systemFontOfSize:15];        }                //清界面--        for (UIView *view in cell.subviews) {            if ([view isKindOfClass:[UIImageView class]]) {                [view removeFromSuperview];            }            if ([view isKindOfClass:[UILabel class]]) {                [view removeFromSuperview];            }        }                        NSDictionary *dic = self.listArray[indexPath.section];        NSArray *cellArray = [NSArray arrayWithArray:dic[@"data"]];        NSString *title = [NSString stringWithFormat:@"%@",dic[@"title"]];        if ([title isEqualToString:@"汇款凭证"]) {                        cell.textLabel.text = @"";            cell.detailTextLabel.text = @"";            _paymentImg = [[UIImageView alloc] initWithFrame:CGRectMake((mainWidth-255)/2, 15, 255, 160)];            [cell addSubview:_paymentImg];            //判断下imgView            _paymentImg.image = [UIImage imageNamed:@"A5_2_payment"];                    }else{            cell.textLabel.text = cellArray[indexPath.row];            cell.detailTextLabel.text = [NSString stringWithFormat:@"test%ld-%ld",indexPath.section,indexPath.row];        }        cell.layer.masksToBounds = YES;        return cell;    }}-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    if (indexPath.section == 0) {        if (self.orderType ==FinancierAcceptTradingType ||self.orderType ==FinancierAcceptCancelType) {            return 140;        }        return 104;    }    NSDictionary *dic = self.listArray[indexPath.section];    NSString *title = [NSString stringWithFormat:@"%@",dic[@"title"]];    if ([title isEqualToString:@"汇款凭证"]) {        return 190;    }        return 44;}-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    [tableView deselectRowAtIndexPath:indexPath animated:YES];    }- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{    if (section == 0) {        return 0.01;    }else if (section == self.listArray.count-1)    {        return 0.01;    }    return 44;    }- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{    return 10;}-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{        if (section == 0 || (section == self.listArray.count-1)) {        UIView *view = [[UIView alloc] init];        return view;    }else{        FinancierHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"header"];        if (!headerView) {            headerView = [[FinancierHeaderView alloc] initWithReuseIdentifier:@"header"];        }        NSDictionary *dic = self.listArray[section];        NSString *title = [NSString stringWithFormat:@"%@",dic[@"title"]];        [headerView setFoldSectionHeaderViewWithTitle:title  section:section canFold:YES];        headerView.delegate = self;        NSString *key = [NSString stringWithFormat:@"%d", (int)section];        BOOL folded = [[_foldInfoDic objectForKey:key] boolValue];        headerView.fold = folded;        return headerView;    }    }- (void)foldHeaderInSection:(NSInteger)SectionHeader {    NSString *key = [NSString stringWithFormat:@"%d",(int)SectionHeader];    BOOL folded = [[_foldInfoDic objectForKey:key] boolValue];    NSString *fold = folded ? @"0" : @"1";    [self.foldInfoDic setObject:fold forKey:key];    //    NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:SectionHeader];    //    [_tableView reloadSections:set withRowAnimation:UITableViewRowAnimationNone];    //刷整个section    NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:SectionHeader];    [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];            //展开    //    if (folded) {    //        [_tableView reloadSections:set withRowAnimation:UITableViewRowAnimationBottom];    //    //    } else { //收起    //        [_tableView reloadSections:set withRowAnimation:UITableViewRowAnimationTop];    //    }}
其中,FinancierHeaderView自定义的tableHeaderView

FinancierHeaderView.h


#import <UIKit/UIKit.h>@protocol FinancierHeaderViewCellDelegate <NSObject>- (void)foldHeaderInSection:(NSInteger)SectionHeader;@end@interface FinancierHeaderView : UITableViewHeaderFooterView@property(nonatomic,strong) UIImageView *rightImg;@property(nonatomic,strong) UIView *headerView;@property(nonatomic,strong) UIButton* rightBtn;@property(nonatomic,strong) UILabel*titleLb;@property(nonatomic,assign) NSInteger index;@property(nonatomic,weak)id<FinancierHeaderViewCellDelegate> delegate;@property(nonatomic, assign) BOOL fold;/**< 是否折叠 */@property(nonatomic, assign) NSInteger section;/**< 选中的section */- (void)setFoldSectionHeaderViewWithTitle:(NSString *)title section:(NSInteger)section canFold:(BOOL)canFold;@end

FinancierHeaderView.m

#import "FinancierHeaderView.h"@interface FinancierHeaderView(){    BOOL _created;/**< 是否创建过 */    BOOL _canFold;/**< 是否可展开 */    }@end@implementation FinancierHeaderView- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier{        self = [super initWithReuseIdentifier:reuseIdentifier];        if (self) {        //        [self setUpUI];//_init表示初始化方法    }        return self;}- (void)setFoldSectionHeaderViewWithTitle:(NSString *)title section:(NSInteger)section canFold:(BOOL)canFold{    if (!_created) {        [self setUpUI];    }    _titleLb.text = title;    _section = section;    _canFold = canFold;    if (canFold) {        _rightImg.hidden = NO;    } else {        _rightImg.hidden = YES;    }}- (void)setUpUI{    _created = YES;    CGFloat space = 10;    _headerView = [[UIView alloc] init];    _headerView.backgroundColor = [UIColor whiteColor];    [self addSubview:_headerView];    [_headerView mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.mas_equalTo(0);        make.left.mas_equalTo(0);        make.width.mas_equalTo(mainWidth);        make.height.mas_equalTo(44);    }];        _titleLb = [[UILabel alloc] init];    _titleLb.font = [UIFont systemFontOfSize:15];    [_headerView addSubview:_titleLb];    [_titleLb mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.mas_equalTo(0);        make.left.mas_equalTo(space);        make.width.mas_equalTo(mainWidth-50);        make.height.mas_equalTo(44);    }];            _rightImg = [[UIImageView alloc] initWithFrame:CGRectMake(mainWidth-40, 17, 20, 10)];    _rightImg.image = [UIImage imageNamed:@"A5_up"];    [_headerView addSubview:_rightImg];    [_rightImg mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.mas_equalTo(17);        make.left.mas_equalTo(mainWidth-40);        make.width.mas_equalTo(20);        make.height.mas_equalTo(10);    }];                _rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];    _rightBtn.selected = YES;    [_rightBtn addTarget:self action:@selector(rightBtnClick:) forControlEvents:UIControlEventTouchUpInside ];    [_headerView addSubview:_rightBtn];    [_rightBtn mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.mas_equalTo(0);        make.left.mas_equalTo(0);        make.width.mas_equalTo(mainWidth);        make.height.mas_equalTo(44);    }];                UIView *lineView = [[UIView alloc] init];    lineView.backgroundColor = [UIColor groupTableViewBackgroundColor];    [_headerView addSubview:lineView];    [lineView mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.mas_equalTo(43.6);        make.left.mas_equalTo(0);        make.width.mas_equalTo(mainWidth);        make.height.mas_equalTo(0.4);    }];}- (void)rightBtnClick:(UIButton *)sender{    if (_canFold) {        if ([self.delegate respondsToSelector:@selector(foldHeaderInSection:)]) {            [self.delegate foldHeaderInSection:_section];        }    }}- (void)setFold:(BOOL)fold {    _fold = fold;    if (fold) {        _rightImg.image = [UIImage imageNamed:@"A5_up"];    } else {        _rightImg.image = [UIImage imageNamed:@"A5_down"];    }}@end

OK,以后有空在整理下第二种方式的代码