UITableView相关知识点

UITableView相关知识点

//*****UITableView相关知识点*****//

  1 #import "ViewController.h"

 // step1 要实现UITableViewDataSource协议,因为tableView不存储数据
@interface ViewController () <UITableViewDataSource, UITableViewDelegate> // step0 准备要显示的数据
@property(nonatomic,strong) NSMutableArray *dataArrM; @property(nonatomic,strong) UITableView *myTable; // 这个数组保存着每个分组的折叠状态
@property(nonatomic,strong) NSMutableArray *sectionShowArrM; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
[self myTable]; // 设置导航条
[self setNavigation ];
} -(void)setNavigation{ UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]initWithTitle:@"Edit" style:UIBarButtonItemStylePlain target:self action:@selector(tableEdit:)]; self.navigationItem.rightBarButtonItem = rightItem;
}
// 点击导航右侧编辑按钮时,让表格可编辑
-(void)tableEdit:(UIBarButtonItem *) btnItem{ if (self.myTable.editing == NO ) { // 没有处于编辑状态,导航按钮文字为“Edit”
// 点击“编辑”文字,让表格处于编辑状态,并把按钮的文字修改为“Done"
self.myTable.editing = YES;
btnItem.title = @"Done";
// 创建一个新删除按钮
UIBarButtonItem *deleteBtn = [[UIBarButtonItem alloc]initWithTitle:@"Delete" style:UIBarButtonItemStylePlain target:self action:@selector(DeleteAllSeleted )]; self.navigationItem.rightBarButtonItems = @[btnItem, deleteBtn]; }else{
// 编辑状态下,点击”Done"按钮,取消表格的编辑状态,修改导航按钮文字为"Edit"
self.myTable.editing = NO;
btnItem.title = @"Edit" ;
self.navigationItem.rightBarButtonItems = @[btnItem];
} } // 删除选中的所有行
-(void)DeleteAllSeleted{
// 获取你选中的所有行
NSArray *selectedIndexPaths = self.myTable.indexPathsForSelectedRows;
// 删除数据源
// for (NSIndexPath *indexPath in selectedIndexPaths ) {
// // 0 1 2 3 4 5 6 7 8
// // 1 2 3 4 5 6 7 8
// // 1 3 4 5 6 7 8
// // 1 3 5 6 7 8
// // 0 1 2
// [self.dataArrM[indexPath.section] removeObjectAtIndex:indexPath.row];
// }
// 需要注意的是,一起删除数组中多个元素的时候,需要从数组的大索引值依次向小索引值删除
for (long i = selectedIndexPaths.count - ; i >= ; i-- ) {
NSIndexPath *indexPath = selectedIndexPaths[i];
[self.dataArrM[indexPath.section] removeObjectAtIndex:indexPath.row];
}
// 在表格中删除单元格
[self.myTable deleteRowsAtIndexPaths:selectedIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; for (int i = ; i < self.dataArrM.count; i++ ) {
NSMutableArray *arr = self.dataArrM[i];
for (int j = ; j < arr.count ; j++ ) {
NSLog(@"%@", arr[j]);
}
}
} #pragma mark - tableView 的懒加载
// step2 在当前视图中添加tableView
-(UITableView *)myTable{
if ( !_myTable) {
_myTable =[[ UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; // _myTable = [[UITableView alloc]initWithFrame:CGRectMake(0, 64, self.view.bounds.size.width, self.view.bounds.size.height - 64 ) style:UITableViewStyleGrouped];
[self.view addSubview:_myTable ]; // step3 指定数据源代理, tableview的数据由当前控制器提供
_myTable.dataSource = self; //*********千万别忘记**********
_myTable.delegate = self; //*********千万别忘记********** // 设置表格的footerView
UIView *footerView = [[UIView alloc]initWithFrame:CGRectMake(, , _myTable.frame.size.width, )];
footerView.backgroundColor = [UIColor redColor];
_myTable.tableFooterView = footerView; // 设置表格允许多选
_myTable.allowsMultipleSelection = YES;
_myTable.allowsSelectionDuringEditing = YES;
_myTable.allowsMultipleSelectionDuringEditing = YES;
}
return _myTable;
} #pragma mark - 数组懒加载
-(NSMutableArray *)dataArrM{
if ( !_dataArrM ) {
_dataArrM = [NSMutableArray array];
for (int i = ; i < ; i++ ) {
NSMutableArray *sectionArrM = [NSMutableArray array];
for (int j = ; j < ; j++ ) {
NSString *str = [NSString stringWithFormat:@"第%d组,第%d行", i ,j ];
[sectionArrM addObject:str];
} [_dataArrM addObject:sectionArrM];
}
}
return _dataArrM;
} #pragma mark - 分组是否折叠数据的懒加载
-(NSMutableArray *)sectionShowArrM{
if (!_sectionShowArrM ) {
_sectionShowArrM = [NSMutableArray array];
for (int i = ; i < self.dataArrM.count ; i++ ) {
[_sectionShowArrM addObject:@NO]; // 默认起始状态为收起
}
}
return _sectionShowArrM;
} // step4 实现UITableViewDataSource协议方法
#pragma mark - UITableViewDataSource
// 返回有多少分组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return self.dataArrM.count;
}
// 指定每个分组有多少行,返回0行表示该分组不显示单元格
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([self.sectionShowArrM[section] boolValue] == YES) {
// 如果sectionShowArrM数组中保存当前分组的状态是YES,为展开状态,返回数组元素的个数
return [self.dataArrM[section] count];
}else{
return ; // 收起状态
} }
// 指定要显示的单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 注册单元格类,并指定重用标识
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellID"];
// 从tableView中找一个可重用的单元格,如果没有的话,系统会自动创建一个新的单元格
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID" forIndexPath:indexPath];
// 指定单元格要显示的内容
cell.textLabel .text = self.dataArrM[indexPath.section][indexPath.row]; //返回单元格
return cell;
}
// 每个分组的头标题
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return [NSString stringWithFormat:@"第%ld组的头", section];
}
// 每个分组尾部的标题
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
return [NSString stringWithFormat:@"第%ld组的尾部", section]; } // 指示是否允许编辑,具体的删除和插入操作由其他协议方法实现
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
} // 指示表格中的行是否可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
} // 返回组索引的标题
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView{
NSMutableArray *sectionTitles = [NSMutableArray array];
for (int i = ; i < self.dataArrM.count ; i++ ) {
[sectionTitles addObject: [NSString stringWithFormat:@"%d组", i ]];
}
return sectionTitles;
} //- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index{
// if (index == 2 ) {
// return 0;
// }else {
// return index;
// }
//} // 提交单元格的编辑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// 在数据源数组中删除相应的数据
[self.dataArrM[indexPath.section] removeObjectAtIndex:indexPath.row];
// 刷新表格
[self.myTable deleteRowsAtIndexPaths:@[indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];
}else if ( editingStyle == UITableViewCellEditingStyleInsert){
// 在数据源数组中插入数据
[self. dataArrM[indexPath.section] insertObject:@"新插入的行" atIndex:indexPath.row ];
// 刷新单元格
[self.myTable insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
} }
// 在该方法中一般实现数据源的交换
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
// 取出要移动行的内容
NSString *row = self.dataArrM[sourceIndexPath.section][sourceIndexPath.row];
// 在数据源中删除要移动的行
[self.dataArrM[sourceIndexPath.section] removeObjectAtIndex:sourceIndexPath.row];
// 在目的地插入要移动的行数据
[self.dataArrM[destinationIndexPath.section] insertObject:row atIndex:destinationIndexPath.row];
} #pragma mark - UITableViewDelegate
// 将要显示每个分组的footer的时候调用
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section{ // if (section < self.dataArrM.count - 1 ) {
// return;
// }
//
// //获取更多数据
// NSMutableArray *addRowsArrM = [NSMutableArray array];
// for (int i = 0 ; i < 10 ; i++ ) {
// NSString *addRow = [NSString stringWithFormat:@"新添加的第%d行", i ];
// [addRowsArrM addObject:addRow];
// }
// [self.dataArrM addObject:addRowsArrM];
// //刷新表格
// NSIndexSet *indexSet = [[NSIndexSet alloc]initWithIndex:section];
// [self.myTable reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
} // 返回第一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return ;
}
// 返回每个分组头部的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return ;
}
// 返回每个分组尾部的高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return ;
} // 返回每个分组头部视图,如果实现了这个协议,tableView:titileForHeaderInSection协议方法不再起作用
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UIButton *headerBtn = [[UIButton alloc]initWithFrame:CGRectMake(, , tableView.frame.size.width, )];
[headerBtn setTitle:[NSString stringWithFormat: @"这是第%ld组的头部", section] forState:UIControlStateNormal] ;
headerBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
headerBtn.backgroundColor = [UIColor orangeColor]; // [headerBtn setImage:[UIImage imageNamed:@"icon_back_highlighted"] forState:UIControlStateNormal];
UIImageView *btnImg = [[UIImageView alloc]initWithFrame:CGRectMake(, , , headerBtn.frame.size.height)];
btnImg.contentMode = UIViewContentModeScaleAspectFit;
btnImg.image = [UIImage imageNamed:@"icon_back_highlighted"];
[headerBtn addSubview:btnImg]; // 根据当前分组是否折叠来确定图标的旋转
BOOL isShow = [self.sectionShowArrM[section] boolValue];
if (isShow == YES) {
btnImg.transform = CGAffineTransformRotate(btnImg.transform, -M_PI_2);
}else{
btnImg.transform = CGAffineTransformIdentity;
} headerBtn.tag = + section;
// 添加事件
[headerBtn addTarget:self action:@selector(showSection: ) forControlEvents:UIControlEventTouchUpInside]; return headerBtn;
}
-(void)showSection:(UIButton *)button{
long sectionIndex = button.tag - ;
// 先获取当前分组的折叠状态
BOOL isShow = [self.sectionShowArrM[sectionIndex] boolValue];
if (isShow == NO ) { // 如果收起状态,点一下后,修改为展开状态
self.sectionShowArrM[sectionIndex] = @YES;
}else { // 展开状态
self.sectionShowArrM[sectionIndex] = @NO;
}
// 刷新当前分组
NSIndexSet *indexSet = [[NSIndexSet alloc] initWithIndex:sectionIndex];
[self.myTable reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic]; // 让分组头部左侧的图标旋转,这块代码放在这儿不合适,表格刷新后,图标会复位
// 获取当前按钮中的箭头
// UIImageView *btnImg;
// for (UIView *subView in button.subviews) {
// if ([subView isKindOfClass:[UIImageView class]]) {
// btnImg = (UIImageView *)subView;
// break;
// }
// }
//
// btnImg.transform = CGAffineTransformRotate(btnImg.transform , -M_PI_2);
} // 返回每个分组尾部视图
// - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
//
// } // 返回单元格右侧的辅助按钮的类型
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellAccessoryDisclosureIndicator;
}
// 当单元格右侧的辅助视图是一个按钮,当点击该按钮时,执行该协议方法
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
NSLog(@"detailButton be tapped");
} // 指示是否允许高亮显示选中的行
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
} // 选中某行时执行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"selected: %ld, row:%ld", indexPath.section, indexPath.row);
}
// 取消选中时执行,这个方法常在表格允许多选时调用执行
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"Deselected: %ld, row:%ld", indexPath.section, indexPath.row);
} // 返回编辑时,是删除单元格还是插入单元格,要真正的实现删除或者插入操作,必须实现tableView:commitEditingStyle:forRowAtIndexPath:这个协议方法
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleInsert;
} // 单元格的缩进
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row % == ){
return ;
}else{
return ;
}
} @end

UITableView相关知识点

04-19 21:46