033-UITableViewHeaderFooterView-iOS笔记

/ 0

学习目标

1.【掌握】静态单元格应用

2.【掌握】动态原型应用

3.【理解】UITableViewHeaderFooterView

一、静态单元格应用

这个案例的目的是了解静态单元格的使用场合及操作方式,在一些情况下使用静态单元格会更加方便和快捷。我们需要了解静态单元格的一些特性及设置方式。案例效果图如下:

20151

静态单元格只支持UITableViewController,所以先将之前的viewController删除。拖入UITableViewController,设置Size属性。再选择UITableView并设置属性Content属性为Static Cells

201512

Dynamin ProtoTypes:动态单元格,通过代码进行设置

Static Cells:静态单元格,通过界面进行设置,固定的。

设置每一组cell的数量:默认每一组有三个cell,修改每一组cell的数量。

201513

设置cell的高度:Cell的高度也就是tableview的row height属性。

201514

设置cell的显示样式:这里的样式和代码创建cell的系统提供的样式类似,不过多了一个Custom自定义。

201515

设置cell的图片:给Cell设置图片,也就是Cell的image属性赋值。

201516

设置cell的文本:

201517

完成上面的操作后我们可以添加任意组(sections),设置对应组的行数(rows)。

需要注意的是,当我们删除原有控制器,创建新控制器后需要将新控制器设为初始显示的控制器。也就是勾选Is Initial View Controller,否则启动模拟器看不到界面。如下图所示:

QQ20150819-1

二、动态原型应用

上面演示了静态单元格的使用,下面接着演示动态原型的使用,也就是UITableView的Content属性中的Dynamic protoTypes。设置这个属性后,我们可以通过代码根据原型动态创建Cell。下面来看看一个应用管理的案例,案例效果图如下:

1

首先,创建项目,导入素材图片和plist文件。

Snip20150821_3

创建模型类,加载plist文件中的数据封装模型,并返回模型数组。

JFApp.h

#import <Foundation/Foundation.h>

@interface JFApp : NSObject
@property (copy, nonatomic) NSString *size;
@property (copy, nonatomic) NSString *download;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *icon;

//快速创建模型
- (instancetype)initWithDictionary:(NSDictionary *)dict;
+ (instancetype)appWithDictionary:(NSDictionary *)dict;

//返回模型数组
+ (NSArray *)apps;
@end

 JFApp.m

#import "JFApp.h"

@implementation JFApp

//快速创建模型
- (instancetype)initWithDictionary:(NSDictionary *)dict {
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
+ (instancetype)appWithDictionary:(NSDictionary *)dict {
    return [[self alloc] initWithDictionary:dict];
}

//返回模型数组
+ (NSArray *)apps {
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps_full.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        JFApp *app = [JFApp appWithDictionary:dict];
        [arrayM addObject:app];
    }
    return arrayM;
}

@end

在Main.storyboard中修改size为4.7,拖入一个全屏的UITableView控件,再拖入一个UITableViewCell控件到UITableView中,并拖入Cell的子控件。Cell的高度也就是tableview的rowheight属性,tableview的content属性默认就是Dynamic prototypes(动态原型),所以无需更改。

Snip20150821_6

创建Cell封装类,并指定Cell的Class属性为我们创建的封装类JFAppCell。

Snip20150821_8指定Class后即可进行属性连线,一般属性连线我们都封装在类扩展(匿名分类,也叫延展)里,而不是.h文件中。

Snip20150821_9设置Cell的重用标识符(Identifier),并在类中定义一个模型属性和快速创建Cell的方法并实现。点击下载按钮后,会弹出一个提示,弹出的提示不会跟随tableview滚动,所以需要添加这个提示View到tableview的父视图中。这样就必须访问控制器,所以我们使用代理来完成这个操作,让控制器成为代理对象,替Cell完成点击事件。

Snip20150821_10

JFAppCell.h

#import <UIKit/UIKit.h>
@class JFApp;
@class JFAppCell;

//定义一个代理
@protocol JFAppCellDelegate <NSObject>

@required
- (void)downloadButtonDidClick:(JFAppCell *)appCell;

@end


@interface JFAppCell : UITableViewCell

//为子控件赋值的模型属性
@property (strong, nonatomic) JFApp *app;

//代理属性
@property (weak, nonatomic) id<JFAppCellDelegate> delegate;

//快速创建cell的方法
+ (instancetype)appCellWithDictionary:(UITableView *)tableView;
@end

 JFAppCell.m

#import "JFAppCell.h"
#import "JFApp.h"

@interface JFAppCell ()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameView;
@property (weak, nonatomic) IBOutlet UILabel *messageView;
@property (weak, nonatomic) IBOutlet UIButton *downloadView;

//下载按钮的点击事件
- (IBAction)downloadButtonDidClick;
@end

@implementation JFAppCell


//下载按钮的点击事件
- (IBAction)downloadButtonDidClick {
    
    //点击下载按钮后禁用下载按钮
    self.downloadView.enabled = NO;
    
    //弹出下载信息,弹出View是添加View到Tableview的父容器中,这里无法访问到。所以得用代理
    if ([self.delegate respondsToSelector:@selector(downloadButtonDidClick:)]) {
        [self.delegate downloadButtonDidClick:self];
    }
}

//快速创建cell的方法
+ (instancetype)appCellWithDictionary:(UITableView *)tableView {
    
    //用cell重用标识符创建cell,这一步前必须在Cell中设置他的Identifier属性
    JFAppCell *cell = [tableView dequeueReusableCellWithIdentifier:@"app"];
    
    return cell;
}

//重写set方法为Cell的子控件赋值
- (void)setApp:(JFApp *)app {
    _app = app;
    
    //图标
    self.iconView.image = [UIImage imageNamed:app.icon];
    
    //名称
    self.nameView.text = app.name;
    
    //下载信息
    self.messageView.text = [NSString stringWithFormat:@"大小:%@M | 下载量:%@万",app.size,app.download];
}
@end

在控制器对tableview进行控件连线,然后懒加载模型数组,并实现数据源方法和Cell的代理方法。最终实现我们的需求,具体控制器中的代码如下:

ViewController.m

#import "ViewController.h"
#import "JFApp.h"
#import "JFAppCell.h"

@interface ViewController () <UITableViewDataSource,JFAppCellDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSArray *apps;

@end

@implementation ViewController

//隐藏顶部状态栏
- (BOOL)prefersStatusBarHidden {
    return YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.tableView.dataSource = self;
    
}

//懒加载
- (NSArray *)apps {
    if (_apps == nil) {
        _apps = [JFApp apps];
    }
    return _apps;
}

//每组一共有多少行数据
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.apps.count;
}

//创建cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    //获取当前数据模型
    JFApp *app = self.apps[indexPath.row];
    
    //创建cell
    JFAppCell *cell = [JFAppCell appCellWithDictionary:tableView];
    
    //指定Cell的代理对象
    cell.delegate = self;
    
    //为Cell赋值
    cell.app = app;
    
    return cell;
}

//实现Cell的代理方法,在下载按钮被点击后触发
- (void)downloadButtonDidClick:(JFAppCell *)appCell {
    
    //创建提示Label
    UILabel *downMessage = [[UILabel alloc] init];
    
    //计算并设置frame
    CGFloat downW = 200;
    CGFloat downH = 20;
    CGFloat downX = (self.view.frame.size.width - downW) / 2;
    CGFloat downY = (self.view.frame.size.height - downH) / 2;
    downMessage.frame = CGRectMake(downX, downY, downW, downH);
    
    //设置一些属性
    downMessage.text = [NSString stringWithFormat:@"%@正在下载...",appCell.app.name];
    downMessage.backgroundColor = [UIColor grayColor];
    downMessage.textAlignment = NSTextAlignmentCenter;
    downMessage.alpha = 0;
    
    //添加到self.view中
    [self.view addSubview:downMessage];
    
    //以动画形式弹出提示并隐藏,最终移除
    [UIView animateWithDuration:1 animations:^{
        downMessage.alpha = 0.7;
    } completion:^(BOOL finished) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:1 animations:^{
                downMessage.alpha = 0;
            } completion:^(BOOL finished) {
                [downMessage removeFromSuperview];
            }];
        });
    }];
    
}

@end

三、UITableViewHeaderFooterView

UITableViewHeaderFooterView是一个定义列表头部视图、列表尾部视图的类,HeaderFooterView一般是用在列表的头部,显示不同的分组状态信息。我们通过QQ分组来演示自定义HeaderFooterView的方法,下面是完成后的效果图:

3

导入素材和plist文件,从下图可以看出,我们需要创建嵌套模型,也就是每一个组好友和每一个好友都需要封装模型。

Snip20150821_11

先封装单个好友模型,是否是vip定义为BOOL类型。

JFFriend.h

#import <Foundation/Foundation.h>

@interface JFFriend : NSObject
@property (copy, nonatomic) NSString *icon;
@property (copy, nonatomic) NSString *intro;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic, getter=isVip) BOOL vip;

//快速创建模型数组
- (instancetype)initWithDictionary:(NSDictionary *)dict;
+ (instancetype)friendWithDictionary:(NSDictionary *)dict;

@end

 JFFriend.m

#import "JFFriend.h"

@implementation JFFriend

//快速创建模型数组
- (instancetype)initWithDictionary:(NSDictionary *)dict {
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
+ (instancetype)friendWithDictionary:(NSDictionary *)dict {
    return [[self alloc] initWithDictionary:dict];
}
@end

然后再封装一组好友的模型,因为好友分组是有收起、展开两种状态的,所以定义一个BOOL类型来存储好友组的状态。

JFFriendGroup.h

#import <Foundation/Foundation.h>

@interface JFFriendGroup : NSObject
@property (strong, nonatomic) NSArray *friends;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) int online;

//是否陈列出好友列表,默认不陈列
@property (assign, nonatomic, getter=isDisplay) BOOL display;

//快速创建组模型
- (instancetype)initWithDictionary:(NSDictionary *)dict;
+ (instancetype)friendGroupWithDictionary:(NSDictionary *)dict;

//返回组模型数组
+ (NSArray *)friendGroups;
@end

JFFriendGroup.m

#import "JFFriendGroup.h"
#import "JFFriend.h"

@implementation JFFriendGroup

//快速创建组模型
- (instancetype)initWithDictionary:(NSDictionary *)dict {
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
        
        //这样赋值后friends数组中是字典,需要转模型
        NSMutableArray *arrayM_temp = [NSMutableArray array];
        for (NSDictionary *dict_temp in self.friends) {
            JFFriend *myFriend = [JFFriend friendWithDictionary:dict_temp];
            [arrayM_temp addObject:myFriend];
        }
        self.friends = arrayM_temp;
    }
    return self;
}
+ (instancetype)friendGroupWithDictionary:(NSDictionary *)dict {
    return [[self alloc] initWithDictionary:dict];
}

//返回组模型数组
+ (NSArray *)friendGroups {
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        JFFriendGroup *friendGroup = [JFFriendGroup friendGroupWithDictionary:dict];
        [arrayM addObject:friendGroup];
    }
    return arrayM;
}
@end

封装Cell类,这里的Cell是指好友而不是分组。也就是每一个Cell显示一个好友的信息,所以我们定义的模型属性是好友模型而不是好友分组模型。并且这里使用系统提供的Cell样式已经能够满足我们的需求,所以无需再手动创建。具体Cell类代码入下:

JFFriendCell.h

#import <UIKit/UIKit.h>
@class JFFriend;

@interface JFFriendCell : UITableViewCell
@property (strong, nonatomic) JFFriend *myFriend;

//快速创建cell
+ (instancetype)friendCellWithTableView:(UITableView *)tableView;

@end

 JFFriendCell.m

#import "JFFriendCell.h"
#import "JFFriend.h"

@implementation JFFriendCell

//快速创建cell
+ (instancetype)friendCellWithTableView:(UITableView *)tableView {
    
    static NSString *ID = @"myFriend";
    
    //从缓存中创建Cell
    JFFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        //系统自带的样式已经能够满足我们的需求,所以无需手动创建,直接使用合适系统提供的cell样式
        cell = [[JFFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    return cell;
}

//重写set方法为Cell赋值
- (void)setMyFriend:(JFFriend *)myFriend {
    
    _myFriend = myFriend;
    
    //为Cell赋值
    self.imageView.image = [UIImage imageNamed:myFriend.icon];
    self.textLabel.text = myFriend.name;
    self.detailTextLabel.text = myFriend.intro;
    
    //如果是vip则昵称是红色
    if (myFriend.isVip) {
        self.textLabel.textColor = [UIColor redColor];
    }
}
@end

封装好模型和Cell后我们就可以在控制器进行调用了,先显示出数据,再根据我们的需求进行修改。我们的QQ列表整个都是tableview,所以不用使用ViewController,直接使用TableviewController。在Main.storyboard中删除原有的ViewController拖入一个TableviewController

Snip20150821_14

然后再修改ViewController.h的继承父类为UITableViewController,才能设置新的控制器所属Class为这个类。

#import <UIKit/UIKit.h>
//修改继承的父类为UITableViewController
@interface ViewController : UITableViewController

@end

设置UITableViewControllerClass属性为ViewController,我们也可以新创建一个类继承自UITableViewController,然后在这里设置Class为我们新创建的那个类。

Snip20150821_15在控制器中懒加载数据,实现数据源方法显示出数据。因为我们Main.storyboard中使用的是TableViewController,所以无需手动遵守数据源、代理协议和手动指定数据源对象、代理对象。

ViewController.m

#import "ViewController.h"
#import "JFFriendGroup.h"
#import "JFFriendCell.h"
#import "JFFriend.h"

@interface ViewController ()
@property (strong, nonatomic) NSArray *friendGroups;

@end

@implementation ViewController

//隐藏状态栏
- (BOOL)prefersStatusBarHidden {
    return YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

//懒加载
- (NSArray *)friendGroups {
    if (_friendGroups == nil) {
        _friendGroups = [JFFriendGroup friendGroups];
    }
    return _friendGroups;
}

//一共多少组,每一个小组就是一组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.friendGroups.count;
}

//每组多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    //获取组模型
    JFFriendGroup *friendGroup = self.friendGroups[section];
    
    return friendGroup.friends.count;
}

//创建Cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    //获取组模型
    JFFriendGroup *friendGroup = self.friendGroups[indexPath.section];
    
    //获取单个好友模型
    JFFriend *myFriend = friendGroup.friends[indexPath.row];
    
    //创建cell
    JFFriendCell *cell = [JFFriendCell friendCellWithTableView:tableView];
    
    //为Cell赋值
    cell.myFriend = myFriend;
    
    return cell;
    
}

@end

 完成后的效果为:

2

数据已经显示出来了,但是没有进行分组。如果我们使用系统自带的分组样式,是无法满足需求的。比如整个分组头部可以点击,并且带小图标,说明这整个分组头部是一个按钮,并且按钮上还有一个Label用来显示在线人数。

下面开始自定义ViewHeaderFooterView,创建一个类并继承自UITableViewHeaderFooterView类。headerView点击后会展开列表,也就是会刷新tableview,这个操作在headerView中是无法完成的(不能将控制器做参数传递)。所以我们通过代理来完成,让控制器成为headerView的代理对象,并实现对应的代理方法来完成这个需求。

 JFHeaderView.h

#import <UIKit/UIKit.h>
@class JFFriendGroup;
@class JFHeaderView;

@protocol JFHeaderViewDelegate <NSObject>

- (void)headerViewButtonDidClick:(JFHeaderView *)headerView;

@end

@interface JFHeaderView : UITableViewHeaderFooterView

//返回一个headerView
+ (instancetype)headerViewWithTableView:(UITableView *)tableView;

@property (strong, nonatomic) JFFriendGroup *friendGroup;

//headerView的代理属性
@property (weak, nonatomic) id<JFHeaderViewDelegate> delegate;
@end

 JFHeaderView.m

#import "JFHeaderView.h"
#import "JFFriendGroup.h"

@interface JFHeaderView ()
@property (weak, nonatomic) UIButton *btn;//headerView按钮
@property (weak, nonatomic) UILabel *lbl;//在线人数

@end

@implementation JFHeaderView

//返回一个headerView
+ (instancetype)headerViewWithTableView:(UITableView *)tableView {
    
    static NSString *headerID = @"header";
    
    JFHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerID];
    
    if (headerView == nil) {
        headerView = [[JFHeaderView alloc] initWithReuseIdentifier:headerID];
    }
    
    return headerView;
}

//重写initWithReuseIdentifier:方法创建自定义headerView
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
    
    if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
        
        UIButton *btn = [[UIButton alloc] init];
        
        [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
        [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
        [btn setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
        btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        btn.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        btn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        btn.imageView.contentMode = UIViewContentModeCenter;
        btn.imageView.clipsToBounds = NO;
        
        //添加到headerView
        [self addSubview:btn];
        self.btn = btn;
        [self.btn addTarget:self action:@selector(headerViewButtonDidClick) forControlEvents:UIControlEventTouchUpInside];
        
        UILabel *lbl = [[UILabel alloc] init];
        
        //文本右对齐
        lbl.textAlignment = NSTextAlignmentRight;
        
        [self addSubview:lbl];
        self.lbl = lbl;
        
    }
    return self;
}

//按钮单击事件
- (void)headerViewButtonDidClick {
    
    self.friendGroup.display = !self.friendGroup.isDisplay;
    
    if ([self.delegate respondsToSelector:@selector(headerViewButtonDidClick:)]) {
        [self.delegate headerViewButtonDidClick:self];
    }
}

//当一个新的headerView已经添加到某个父控件中的时候调用这个方法
- (void)didMoveToSuperview {
    if (self.friendGroup.isDisplay) {
        self.btn.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    } else {
        self.btn.imageView.transform = CGAffineTransformMakeRotation(0);
    }
}

//重写set方法为headerView赋值
- (void)setFriendGroup:(JFFriendGroup *)friendGroup {
    
    _friendGroup = friendGroup;
    
    //设置组名
    [self.btn setTitle:friendGroup.name forState:UIControlStateNormal];
    
    //设置在线人数
    self.lbl.text = [NSString stringWithFormat:@"%d / %lu",friendGroup.online,friendGroup.friends.count];
}

//当将这个控件真正添加到父控件的时候,会调用这个方法设置当前控件的所有子控件的frame
- (void)layoutSubviews {
    
    [super layoutSubviews];
    
    self.btn.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    
    self.lbl.frame = CGRectMake(300, 0, 60, 44);
}

@end

在控制器中遵守JFHeaderViewDelegate代理协议并实现代理方法,实现单组数据刷新。

ViewController.m

#import "ViewController.h"
#import "JFFriendGroup.h"
#import "JFFriendCell.h"
#import "JFFriend.h"
#import "JFHeaderView.h"

@interface ViewController () <JFHeaderViewDelegate>
@property (strong, nonatomic) NSArray *friendGroups;

@end

@implementation ViewController

//隐藏状态栏
- (BOOL)prefersStatusBarHidden {
    return YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //设置headerView的高度
    self.tableView.sectionHeaderHeight = 50;
    
}

//懒加载
- (NSArray *)friendGroups {
    if (_friendGroups == nil) {
        _friendGroups = [JFFriendGroup friendGroups];
    }
    return _friendGroups;
}

//一共多少组,每一个小组就是一组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.friendGroups.count;
}

//每组多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    //获取组模型
    JFFriendGroup *friendGroup = self.friendGroups[section];
    
    //是否展开好友
    if (friendGroup.isDisplay) {
        return friendGroup.friends.count;
    } else {
        return 0;
    }
}

//创建Cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    //获取组模型
    JFFriendGroup *friendGroup = self.friendGroups[indexPath.section];
    
    //获取单个好友模型
    JFFriend *myFriend = friendGroup.friends[indexPath.row];
    
    //创建cell
    JFFriendCell *cell = [JFFriendCell friendCellWithTableView:tableView];
    
    //为Cell赋值
    cell.myFriend = myFriend;
    
    return cell;
    
}

//创建headerView
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    
    JFFriendGroup *friendGroup = self.friendGroups[section];
    
    JFHeaderView *headerView = [JFHeaderView headerViewWithTableView:tableView];
    
    //存储组
    headerView.tag = section;
    
    //指定控制器为代理
    headerView.delegate = self;
    
    headerView.friendGroup = friendGroup;
    
    return headerView;
    
}

//点击headerView按钮的时候触发
- (void)headerViewButtonDidClick:(JFHeaderView *)headerView {
    
    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:headerView.tag];
    
    //刷新指定组
    [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
    
}

关于重用:

UITableViewHeaderFooterViewUITableViewCell在滑动屏幕时都可以根据标志进行重用,而在不滑动而只进行reloadData等刷新数据操作时,两者有不同表现:UITableViewHeaderFooterView将不能根据标志重用(即系统不会将其放入缓冲区),会创建新的视图代替旧的。UITableViewCell能根据标志重用。所以在自定义UITableViewHeaderFooterView首尾视图时,要注意刷新数据时对视图的处理。