1.没有继承UITableViewHeaderFooterView方法,没有进行优化 // 以下数据源方法都可以不必实现! /** 在表格中,默认情况下,标题是不能接收用户点击的 目前而言,如果让标题能够接收用户的点击,需要自己添加一个按钮 注意: 如果同时重写了标题的字符串方法和自定义视图方法,则自定义视图方法的优先级高! 字符串方法将不被执行 如果要监听标题或者页脚中的点击事件,注意给按钮添加tag属性,以加以区分 */ #pragma mark 标题内容 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSLog(@"标题行字符串"); NSString *str = [NSString stringWithFormat:@"第%d组xxxxx", section]; return str; } #pragma mark 自定义标题视图 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSLog(@"标题行自定义视图xxxx"); // 1. 实例化标题视图,标题的自定义视图宽度最好不要写死 UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 44)]; [view setBackgroundColor:[UIColor lightGrayColor]]; // 2. 在标题视图中添加一个按钮 UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; NSString *str = [NSString stringWithFormat:@"pppp第%d组", section]; [button setTitle:str forState:UIControlStateNormal]; [button setFrame:view.bounds]; // 3. 添加标题按钮的监听方法 [button setTag:section]; [button addTarget:self action:@selector(clickHeader:) forControlEvents:UIControlEventTouchUpInside]; [view addSubview:button]; // 3. 返回标题视图 return view; } #pragma mark 按钮监听方法 - (void)clickHeader:(UIButton *)button { NSLog(@"点击按钮的分组数%d", button.tag); } 2.进行了性能优化 #pragma mark - 标题行 // 如果是字符串形式,本身不需要进行优化,因为通常会有一个数据字典维护,要显示的字符串,直接通过section从数组中提取即可 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSLog(@"HELLO"); return [NSString stringWithFormat:@"xxxx第%d组", section]; } #pragma mark 自定义视图标题行 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSLog(@"自定义view"); // 使用可重用标示符才能做到表格行的优化 // 要实现标题行的优化,需要实例化:UITableViewHeaderFooterView // 1) 指定static可重用标示符 static NSString *HeaderID = @"MyHeader"; // 2) 使用可重用标示,让表格在缓冲区查找是否存在可重用的标题行视图 UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; // 3) 如果没有找到缓存的标题行视图,则使用可重用标示符实例化新的表格行视图 if (header == nil) { // 必须要使用initWithReuseIdentifier方法,实例化UITableViewHeaderFooterView视图 header = [[UITableViewHeaderFooterView alloc]initWithReuseIdentifier:HeaderID]; [header setFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)]; NSLog(@"实例化标题行 %d", section); // 自定义标题栏视图内容部分的代码,需要写在 header == nil 分支语句中 // 以下代码实际上在通过代码编写自定义视图时的,视图初始化方法的内容 // 注意:对于自定义控件的代码,不要写在分支语句的外部,否则就到不到优化的效果了 UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [button setTitle:@"hellobbbb" forState:UIControlStateNormal]; [button setFrame:header.bounds]; [header addSubview:button]; } NSLog(@"标题行视图的子视图数量:%d", header.subviews.count); return header; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 44; } #pragma mark 分组名称 // UIPickerView中有两种返回的方式:1)字符串,2)自定义UIView - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // 分组的头也需要做优化, // 注意:如果需要分组头优化,需要使用xib文件自定义分组头,或者使用代码的方式自定义分组头控件 static NSString *HeaderID = @"myHeader"; UIView *myHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; if (myHeader == nil) { myHeader = [[UIView alloc]init]; NSLog(@"建立表格标题"); } [myHeader setBackgroundColor:[UIColor orangeColor]]; // 增加三角指示图片 UIImage *image = [UIImage imageNamed:@"disclosure.png"]; UIImageView *imageView = [[UIImageView alloc]initWithImage:image]; [imageView setFrame:CGRectMake(10.0, 9, 32, 32)]; [myHeader addSubview:imageView]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setFrame:CGRectMake(0, 0, 320, 50)]; NSDictionary *dict = _friendsList[section]; [button setTitle:dict[@"group"] forState:UIControlStateNormal]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 用button的tag属性记录section数值 [button setTag:section]; // 监听按钮事件 [button addTarget:self action:@selector(clickHeader:) forControlEvents:UIControlEventTouchUpInside]; [myHeader addSubview:button]; // 可以根据对应的sction设定三角图片的旋转角度 NSInteger sectionStatus = [_sectionInfo[dict[@"group"]]integerValue]; // 如果是0,表示折叠, 如果是1,表示展开,旋转90 if (sectionStatus == 0) { [imageView setTransform:CGAffineTransformMakeRotation(0)]; } else { [imageView setTransform:CGAffineTransformMakeRotation(M_PI_2)]; } return myHeader; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 50.0; } 2.继承UITableViewHeaderFooterView方法 MyHeader.h @class MyHeader; #define kHeaderHeight 44 #pragma mark - 定义协议 @protocol MyHeaderDelegate <NSObject> - (void)myHeaderDidSelectedHeader:(MyHeader *)header; @end #pragma mark - 定义接口 @interface MyHeader : UITableViewHeaderFooterView // 定义代理 @property (weak, nonatomic) id <MyHeaderDelegate> delegate; // 标题栏按钮 @property (weak, nonatomic) UIButton *button; // 标题栏分组 @property (assign, nonatomic) NSInteger section; // 是否展开折叠标记 @property (assign, nonatomic) BOOL isOpen; @end MyHeader.m @implementation MyHeader - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithReuseIdentifier:reuseIdentifier]; if (self) { [self setFrame:CGRectMake(0, 0, 320, kHeaderHeight)]; // 设置渐变颜色 [self setTintColor:[UIColor orangeColor]]; // 增加按钮 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; NSLog(@"实例化标题行 %@", NSStringFromCGRect(self.bounds)); [button setFrame:self.bounds]; // 设置按钮的图片 UIImage *image = [UIImage imageNamed:@"disclosure.png"]; [button setImage:image forState:UIControlStateNormal]; // 设置按钮内容的显示位置 [button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft]; // 给按钮添加监听事件 [button addTarget:self action:@selector(clickButton) forControlEvents:UIControlEventTouchUpInside]; [self.contentView addSubview:button]; self.button = button; } return self; } - (void)clickButton { // 通知代理执行协议方法 [self.delegate myHeaderDidSelectedHeader:self]; } #pragma mark 展开折叠的setter方法 - (void)setIsOpen:(BOOL)isOpen { _isOpen = isOpen; // 旋转按钮 CGFloat angle = isOpen ? M_PI_2 : 0; [UIView animateWithDuration:0.5f animations:^{ [self.button.imageView setTransform:CGAffineTransformMakeRotation(angle)]; }]; } @end #pragma mark 表格标题栏 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // 如果要对标题栏进行优化,需要使用UITableViewHeaderFooterView类型的视图 static NSString *HeaderID = @"MyHeader"; // 1. 在缓冲池查找可重用的标题行 // MyHeader *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; // 从字典中读取标题行 MyHeader *header = self.sectionDict[@(section)]; if (header == nil) { NSLog(@"实例化标题栏"); // 实例化表格标题,一定要用initWithReuseIdentifier方法 header = [[MyHeader alloc]initWithReuseIdentifier:HeaderID]; // 设置代理 [header setDelegate:self]; // 将自定义标题栏加入字典 [self.sectionDict setObject:header forKey:@(section)]; } NSDictionary *dict = self.dataList[section]; NSString *groupName = dict[@"group"]; [header.button setTitle:groupName forState:UIControlStateNormal]; // 在标题栏自定义视图中记录对应的分组数 [header setSection:section]; return header; } #pragma mark - 自定义标题栏代理方法 - (void)myHeaderDidSelectedHeader:(MyHeader *)header { NSLog(@"点击按钮 %d", header.section); // 处理展开折叠 // 需要记录每个分组的展开折叠情况 // BOOL isOpen = [self.sectionStates[@(header.section)]boolValue]; // 从字典中取出标题栏 MyHeader *myHeader = self.sectionDict[@(header.section)]; BOOL isOpen = myHeader.isOpen; [myHeader setIsOpen:!isOpen]; // [self.sectionStates setObject:@(!isOpen) forKey:@(header.section)]; // [header setIsOpen:!isOpen]; // 刷新数据,以下代码是刷新全部数据 // [self.tableView reloadData]; // 在tableView的开发中,如果可能,应该尽量避免去刷新全部数据 // 本应用中,可以刷新指定分组 #warning 此处有陷阱 // 注意:一旦刷新表格数据,表格中的标题行,会重新被实例化,而不会从缓存池中加载 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:header.section] withRowAnimation:UITableViewRowAnimationFade]; }
1.采用系统的方法直接设定
tableview.tableHeaderView //顶部
tableview.tableFooterView //底部
tableview.tableHeaderView = [UIButton buttonWithType:UIButtonTypeContactAdd]; tableview.tableFooterView = [[UISwitch alloc] init];
记录一下,tableHeaderView會隨著底下cell移動到消失,viewForHeaderInSection會一直固定在那裡。直到下一个section来的时候,进行切换
2.采用自定义的方式添加head // 以下数据源方法都可以不必实现! /** 在表格中,默认情况下,标题是不能接收用户点击的 目前而言,如果让标题能够接收用户的点击,需要自己添加一个按钮 注意: 如果同时重写了标题的字符串方法和自定义视图方法,则自定义视图方法的优先级高! 字符串方法将不被执行 如果要监听标题或者页脚中的点击事件,注意给按钮添加tag属性,以加以区分
如果两个都实现的话,只会显示一个,显示view那个, */ #pragma mark 标题内容 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSLog(@"标题行字符串"); NSString *str = [NSString stringWithFormat:@"第%d组xxxxx", section]; return str; } #pragma mark 自定义标题视图 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSLog(@"标题行自定义视图xxxx"); // 1. 实例化标题视图,标题的自定义视图宽度最好不要写死 UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 44)]; [view setBackgroundColor:[UIColor lightGrayColor]]; // 2. 在标题视图中添加一个按钮 UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; NSString *str = [NSString stringWithFormat:@"pppp第%d组", section]; [button setTitle:str forState:UIControlStateNormal]; [button setFrame:view.bounds]; // 3. 添加标题按钮的监听方法 [button setTag:section]; [button addTarget:self action:@selector(clickHeader:) forControlEvents:UIControlEventTouchUpInside]; [view addSubview:button]; // 3. 返回标题视图 return view; } #pragma mark 按钮监听方法 - (void)clickHeader:(UIButton *)button { NSLog(@"点击按钮的分组数%d", button.tag); } //进行了性能优化 #pragma mark - 标题行 // 如果是字符串形式,本身不需要进行优化,因为通常会有一个数据字典维护,要显示的字符串,直接通过section从数组中提取即可 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSLog(@"HELLO"); return [NSString stringWithFormat:@"xxxx第%d组", section]; } #pragma mark 自定义视图标题行 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSLog(@"自定义view"); // 使用可重用标示符才能做到表格行的优化 // 要实现标题行的优化,需要实例化:UITableViewHeaderFooterView // 1) 指定static可重用标示符 static NSString *HeaderID = @"MyHeader"; // 2) 使用可重用标示,让表格在缓冲区查找是否存在可重用的标题行视图 UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; // 3) 如果没有找到缓存的标题行视图,则使用可重用标示符实例化新的表格行视图 if (header == nil) { // 必须要使用initWithReuseIdentifier方法,实例化UITableViewHeaderFooterView视图 header = [[UITableViewHeaderFooterView alloc]initWithReuseIdentifier:HeaderID]; [header setFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)]; NSLog(@"实例化标题行 %d", section); // 自定义标题栏视图内容部分的代码,需要写在 header == nil 分支语句中 // 以下代码实际上在通过代码编写自定义视图时的,视图初始化方法的内容 // 注意:对于自定义控件的代码,不要写在分支语句的外部,否则就到不到优化的效果了 UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [button setTitle:@"hellobbbb" forState:UIControlStateNormal]; [button setFrame:header.bounds]; [header addSubview:button]; } NSLog(@"标题行视图的子视图数量:%d", header.subviews.count); return header; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 44; } #pragma mark 分组名称 // UIPickerView中有两种返回的方式:1)字符串,2)自定义UIView - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // 分组的头也需要做优化, // 注意:如果需要分组头优化,需要使用xib文件自定义分组头,或者使用代码的方式自定义分组头控件 static NSString *HeaderID = @"myHeader"; UIView *myHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; if (myHeader == nil) { myHeader = [[UIView alloc]init]; NSLog(@"建立表格标题"); } [myHeader setBackgroundColor:[UIColor orangeColor]]; // 增加三角指示图片 UIImage *image = [UIImage imageNamed:@"disclosure.png"]; UIImageView *imageView = [[UIImageView alloc]initWithImage:image]; [imageView setFrame:CGRectMake(10.0, 9, 32, 32)]; [myHeader addSubview:imageView]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setFrame:CGRectMake(0, 0, 320, 50)]; NSDictionary *dict = _friendsList[section]; [button setTitle:dict[@"group"] forState:UIControlStateNormal]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 用button的tag属性记录section数值 [button setTag:section]; // 监听按钮事件 [button addTarget:self action:@selector(clickHeader:) forControlEvents:UIControlEventTouchUpInside]; [myHeader addSubview:button]; // 可以根据对应的sction设定三角图片的旋转角度 NSInteger sectionStatus = [_sectionInfo[dict[@"group"]]integerValue]; // 如果是0,表示折叠, 如果是1,表示展开,旋转90 if (sectionStatus == 0) { [imageView setTransform:CGAffineTransformMakeRotation(0)]; } else { [imageView setTransform:CGAffineTransformMakeRotation(M_PI_2)]; } return myHeader; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 50.0; } 3.继承UITableViewHeaderFooterView方法 MyHeader.h @class MyHeader; #define kHeaderHeight 44 #pragma mark - 定义协议 @protocol MyHeaderDelegate <NSObject> - (void)myHeaderDidSelectedHeader:(MyHeader *)header; @end #pragma mark - 定义接口 @interface MyHeader : UITableViewHeaderFooterView // 定义代理 @property (weak, nonatomic) id <MyHeaderDelegate> delegate; // 标题栏按钮 @property (weak, nonatomic) UIButton *button; // 标题栏分组 @property (assign, nonatomic) NSInteger section; // 是否展开折叠标记 @property (assign, nonatomic) BOOL isOpen; @end MyHeader.m @implementation MyHeader - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithReuseIdentifier:reuseIdentifier]; if (self) { [self setFrame:CGRectMake(0, 0, 320, kHeaderHeight)]; // 设置渐变颜色 [self setTintColor:[UIColor orangeColor]]; // 增加按钮 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; NSLog(@"实例化标题行 %@", NSStringFromCGRect(self.bounds)); [button setFrame:self.bounds]; // 设置按钮的图片 UIImage *image = [UIImage imageNamed:@"disclosure.png"]; [button setImage:image forState:UIControlStateNormal]; // 设置按钮内容的显示位置 [button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft]; // 给按钮添加监听事件 [button addTarget:self action:@selector(clickButton) forControlEvents:UIControlEventTouchUpInside]; [self.contentView addSubview:button]; self.button = button; } return self; } - (void)clickButton { // 通知代理执行协议方法 [self.delegate myHeaderDidSelectedHeader:self]; } #pragma mark 展开折叠的setter方法 - (void)setIsOpen:(BOOL)isOpen { _isOpen = isOpen; // 旋转按钮 CGFloat angle = isOpen ? M_PI_2 : 0; [UIView animateWithDuration:0.5f animations:^{ [self.button.imageView setTransform:CGAffineTransformMakeRotation(angle)]; }]; } @end #pragma mark 表格标题栏 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // 如果要对标题栏进行优化,需要使用UITableViewHeaderFooterView类型的视图 static NSString *HeaderID = @"MyHeader"; // 1. 在缓冲池查找可重用的标题行 // MyHeader *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderID]; // 从字典中读取标题行 MyHeader *header = self.sectionDict[@(section)]; if (header == nil) { NSLog(@"实例化标题栏"); // 实例化表格标题,一定要用initWithReuseIdentifier方法 header = [[MyHeader alloc]initWithReuseIdentifier:HeaderID]; // 设置代理 [header setDelegate:self]; // 将自定义标题栏加入字典 [self.sectionDict setObject:header forKey:@(section)]; } NSDictionary *dict = self.dataList[section]; NSString *groupName = dict[@"group"]; [header.button setTitle:groupName forState:UIControlStateNormal]; // 在标题栏自定义视图中记录对应的分组数 [header setSection:section]; return header; } #pragma mark - 自定义标题栏代理方法 - (void)myHeaderDidSelectedHeader:(MyHeader *)header { NSLog(@"点击按钮 %d", header.section); // 处理展开折叠 // 需要记录每个分组的展开折叠情况 // BOOL isOpen = [self.sectionStates[@(header.section)]boolValue]; // 从字典中取出标题栏 MyHeader *myHeader = self.sectionDict[@(header.section)]; BOOL isOpen = myHeader.isOpen; [myHeader setIsOpen:!isOpen]; // [self.sectionStates setObject:@(!isOpen) forKey:@(header.section)]; // [header setIsOpen:!isOpen]; // 刷新数据,以下代码是刷新全部数据 // [self.tableView reloadData]; // 在tableView的开发中,如果可能,应该尽量避免去刷新全部数据 // 本应用中,可以刷新指定分组 #warning 此处有陷阱 // 注意:一旦刷新表格数据,表格中的标题行,会重新被实例化,而不会从缓存池中加载 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:header.section] withRowAnimation:UITableViewRowAnimationFade]; }
浙公网安备 33010602011771号