一、bug展示
在iOS 11之下
UITableView创建方式如下:
self.automaticallyAdjustsScrollViewInsets = NO;
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
[self.view addSubview:tableView];
[tableView setContentInset:UIEdgeInsetsMake(64, 0, 0, 0)];
tableView.backgroundColor = [UIColor redColor];
tableView.delegate = self;
tableView.dataSource = self;
二、bug原因
在新版iOS11中automaticallyAdjustsScrollViewInsets方法被废弃,我们需要使用UIScrollView的 contentInsetAdjustmentBehavior 属性来替代它.
我们先来看看contentInsetAdjustmentBehavior这个枚举值:
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted
UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
} API_AVAILABLE(ios(11.0),tvos(11.0));
- UIScrollViewContentInsetAdjustmentAutomatic 和scrollableAxes一样,scrollView会自动计算和适应顶部和底部的内边距并且在scrollView 不可滚动时,也会设置内边距.
- UIScrollViewContentInsetAdjustmentScrollableAxes 自动计算内边距.
- UIScrollViewContentInsetAdjustmentNever 不计算内边距
- UIScrollViewContentInsetAdjustmentAlways根据safeAreaInsets 计算内边距
如果需要适配项目中self.automaticallyAdjustsScrollViewInsets = NO;
,那么设置为UIScrollViewContentInsetAdjustmentNever
三、全局适配
对于一个iOS 11之前的项目,想要适配该特性,如果在每个视图控制器中去设置将是一个庞大的工作量,所以在这里通过分类的方式全局添加该特性,先贴上源码:
创建UIViewController的一个分类
#import "UIViewController+FLInsert.h"
@implementation UIViewController (VFInsert)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector= @selector(FL_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class,originalSelector);
Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
});
}
- (void)FL_viewWillAppear:(BOOL)animated {
[self FL_viewWillAppear:animated];
UIScrollView *scrollView = nil;
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UITableView class]] || [view isKindOfClass:[UICollectionView class]]) {
scrollView = (UIScrollView *)view;
break;
}
}
if (!self.automaticallyAdjustsScrollViewInsets) {
if (@available(iOS 11.0, *)) {
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
}
else {
if (@available(iOS 11.0, *)) {
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
}
}
}
- (void)FL_setAutomaticallyAdjustsScrollViewInsets:(BOOL)automaticallyAdjustsScrollViewInsets {
[self FL_setAutomaticallyAdjustsScrollViewInsets:automaticallyAdjustsScrollViewInsets];
}
@end
在UIViewController的分类中使用运行时进行方法交换,使用FL_viewWillAppear:(BOOL)animated
方法替换原有viewWillAppear:(BOOL)animated
方法,同时在FL_viewWillAppear:(BOOL)animated
方法再调用viewWillAppear:(BOOL)animated
方法,保证系统viewWillAppear:(BOOL)animated
方法正常运行。然后在FL_viewWillAppear:(BOOL)animated
方法做需要做的事情,找到需要视图控制中的UIScrollView,根据automaticallyAdjustsScrollViewInsets属性给UIScrollView设置对应的contentInsetAdjustmentBehavior属性值。