1. 程式人生 > >【iOS】UITableView中section的展開和收起

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

我們在做專案時,經常遇到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,以後有空在整理下第二種方式的程式碼