【iOS】tableHeaderView的一个巨坑

网上普遍的资料反映的都是UITableView的header view动态变化需要重新给tableHeaderView赋值而不能只给其frame属性赋值

但如果出现需要多次给tableHeaderView赋值的情况时(比如每次进入界面都要刷新用户信息更新header view的数据),就会出现每赋一次值header view和cell的间距就会越大的BUG。

BUG表现:

如果给tableHeaderView赋值的view的frame属性有带有非零小数的浮点数(尤其指.size.height和.origin.y),就会导致这个问题。

具体表现为tableView的cell的位置每赋一次值就会下移一次,下移的数值为小数部分数值。

BUG原因:

从表现分析应该是个系统BUG,对浮点的处理有一定问题,具体原因就只能看大佬解答了。

解决方法:

1.直接保证tableHeaderView的frame都是整数,或是小数部分为0的数;

2.目前公司项目计划使用钩子钩住这个系统函数 setTableHeaderView: ,然后做取整处理。

12.26更新 附上代码实现:(同时对footer view也进行了处理)

#import "FLTableViewHeaderFix.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <UIKit/UIKit.h>

@interface NSObject(FLTableViewHeaderFix)
- (void)origin_setTableHeaderView:(UIView *)headerView;
- (void)origin_setTableFooterView:(UIView *)footerView;
@end

@interface FLTableViewHeaderFix()

@end

@implementation FLTableViewHeaderFix

+ (void)load
{
//    NSLog(@"******** FLTableViewHeaderFix load *******");
    [FLTableViewHeaderFix hookSetTableHeaderView];
    [FLTableViewHeaderFix hookSetTableFooterView];
}

+ (void) hookSetTableHeaderView
{
    Class systemClass = objc_getClass("UITableView");
    SEL systemSelector = @selector(setTableHeaderView:);
    Class replaceClass = [self class];
    SEL replaceSelector = @selector(fix_setTableHeaderView:);
    Method originMethod = NULL;
    Method replaceMethod = NULL;
    originMethod = class_getInstanceMethod(systemClass,systemSelector);
    replaceMethod = class_getInstanceMethod(replaceClass, replaceSelector);
    
    if (originMethod && replaceMethod) {
        IMP originMethod_imp = method_getImplementation(originMethod);
        IMP replaceMethod_imp = method_getImplementation(replaceMethod);
        class_addMethod(systemClass, @selector(origin_setTableHeaderView:), originMethod_imp, method_getTypeEncoding(originMethod));
        class_replaceMethod(systemClass, systemSelector, replaceMethod_imp, method_getTypeEncoding(originMethod));
    }
}

+ (void) hookSetTableFooterView
{
    Class systemClass = objc_getClass("UITableView");
    SEL systemSelector = @selector(setTableFooterView:);
    Class replaceClass = [self class];
    SEL replaceSelector = @selector(fix_setTableFooterView:);
    Method originMethod = NULL;
    Method replaceMethod = NULL;
    originMethod = class_getInstanceMethod(systemClass,systemSelector);
    replaceMethod = class_getInstanceMethod(replaceClass, replaceSelector);
    
    if (originMethod && replaceMethod) {
        IMP originMethod_imp = method_getImplementation(originMethod);
        IMP replaceMethod_imp = method_getImplementation(replaceMethod);
        class_addMethod(systemClass, @selector(origin_setTableFooterView:), originMethod_imp, method_getTypeEncoding(originMethod));
        class_replaceMethod(systemClass, systemSelector, replaceMethod_imp, method_getTypeEncoding(originMethod));
    }
}


- (void)fix_setTableHeaderView:(UIView *)headerView
{
//    NSLog(@"******** FLTableViewHeaderFix fix_setTableHeaderView *******");
    CGRect tmp = headerView.frame;
    tmp.origin.x = ceil(tmp.origin.x);
    tmp.origin.y = ceil(tmp.origin.y);
    tmp.size.height = ceil(tmp.size.height);
    tmp.size.width = ceil(tmp.size.width);
    headerView.frame = tmp;
    [self origin_setTableHeaderView:headerView];
}

- (void)fix_setTableFooterView:(UIView *)footerView
{
    //    NSLog(@"******** FLTableViewHeaderFix fix_setTableFooterView *******");
    CGRect tmp = footerView.frame;
    tmp.origin.x = ceil(tmp.origin.x);
    tmp.origin.y = ceil(tmp.origin.y);
    tmp.size.height = ceil(tmp.size.height);
    tmp.size.width = ceil(tmp.size.width);
    footerView.frame = tmp;
    [self origin_setTableFooterView:footerView];
}

@end

在主工程项目中#import "FLTableViewHeaderFix.h"即可


版权声明:本文为qq_32792839原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。