页眉和页脚
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];
}
View Code

 

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]; }

 

posted on 2015-07-11 11:53  pTrack  阅读(149)  评论(0)    收藏  举报