【iOS】UITableView中section的展開和收起
阿新 • • 發佈:2018-11-02
我們在做專案時,經常遇到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,以後有空在整理下第二種方式的程式碼