iOS纯frame布局里偏移64px的一些坑

前言

我们在手动设置Frame布局时,经常遇到UITableView偏移了64px(iPhone上是88px,下面省略说明),这里总结下,有那些情况会出现偏移。

1. navigationBar.translucent

在iOS 7上开始出现的值,意思是navigationBar是否半透明,默认是YES,当为YES时,打印ViewController.viewUITableView.frame如下:

在viewDidLoad里 po self.view
<UIView: 0x7fc9ecf009d0; frame = (0 0; 414 736)>
在viewWillAppear里 po self.view
<UIView: 0x7fc9ecf009d0; frame = (0 0; 414 736)>
在viewWillAppear里 po self.tableView
<UITableView: 0x7fd491064e00; frame = (0 0; 414 736); contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>
在viewDidAppear里 po self.tableView
<UITableView: 0x7fd491064e00; frame = (0 0; 414 736); contentOffset: {0, -64}; contentSize: {414, 0}; adjustedContentInset: {64, 0, 0, 0}>

可以看到,view的y坐标是从0开始的,也就是iOS7以后,self.view.y默认都是0开始,这时候我们如果设置

tableView.frame = CGRectMake(0,0,self.view.width,self.view.height);

因为self.automaticallyAdjustsScrollViewInsets默认是YES
(iOS 11以后是UIScrollView的 contentInsetAdjustmentBehavior)
所以tableView.contentInset会下移64px,这时候tableView显示是没问题的,只是上滑时候,因为navigationBar的半透明效果会可以看到tableView的内容。

但如果这时候设置

tableView.frame = CGRectMake(0,64,self.view.width,self.view.height);

就会出现tableView的内容下移了64px的问题,同理如果设置

self.automaticallyAdjustsScrollViewInsets = NO
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;//iOS 11

会出现tableView的内容上移了64px,被navigationBar盖住了的问题

当设置translucent = NO;时我们看下打印情况

在viewDidLoad打印 po self.view
<UIView: 0x7fd442485f50; frame = (0 0; 414 736); >
在viewWillAppear打印  po self.view
<UIView: 0x7fd442485f50; frame = (0 64; 414 672); >
在viewWillAppear打印  po self.tableView
<UITableView: 0x7fd443840000; frame = (0 0; 414 736); contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>
在viewDidAppear打印  po self.view
<UIView: 0x7fd442485f50; frame = (0 64; 414 672); >
在viewDidAppear打印  po self.tableView
<UITableView: 0x7fd443840000; frame = (0 0; 414 736);contentOffset: {0, 0}; contentSize: {414, 0}; adjustedContentInset: {0, 0, 0, 0}>

这里会有个很蛋疼问题,可以看到self.view的y和height在didLoadwillAppear里都出现了变化,这时候我们如果在didLoad里用self.view的frame来给tableView设置fame,

tableView.frame = CGRectMake(0,64,self.view.width,self.view.height);

就会出现tableView下移了64px,而且height还多出64px的问题.

2. extendedLayoutIncludesOpaqueBars

同样是iOS 7以后开始有的属性,意思为是否扩大布局到不透明的bar上,默认值是NO,只有NavigationBar为不透明才生效,也就是navigationBar.translucent = NO时。当为YES时,self.view的Y坐标是从0开始的,为NO时,self.view的Y坐标从64开始。
设置extendedLayoutIncludesOpaqueBars得配合navigationBar.translucent = NO使用,有两种组合:

self.navigationController.navigationBar.translucent = NO;
self.extendedLayoutIncludesOpaqueBars = NO;

因为extendedLayoutIncludesOpaqueBars默认为NO,所以这时候效果等同于第一点里单独设置translucent = NO时候的效果。

self.navigationController.navigationBar.translucent = NO;
self.extendedLayoutIncludesOpaqueBars = YES;

当设置extendedLayoutIncludesOpaqueBars为YES时,布局效果等同于第一点里设置translucent = YES的效果,只是少了navigationBar的半透明。

3.automaticallyAdjustsScrollViewInsets

同样是iOS 7 以后出现的属性,平时网上应该是讲这个最多的,iOS11以后被另外一个属性替换了,这个后续再说。这个属性默认为YES,效果就是系统会自动判断是否给ScrollView的contentInsets设置64px的偏移。

总结

上面说的几个属性都是会相互影响的,特别是navigationbar.translucent,会影响整个navigationViewController里的所有viewControoller.所有一般我们不在ViewController专门设置这个属性,具体整个APP里设置YES还是NO,由产品定,iOS7以后默认都是YES,如果想默认为NO的话,在APP启动时设置

[[UINavigationBar appearance] setTranslucent:NO];

根据这几个值的默认值设定,我们APP布局其实只需要简单的设置

tableView.frame = CGRectMake(0,0,self.view.width,self.view.height);

就能达到显示正常的效果,下面列出所有组合,里面有些不太建议的组合,这几种组合都需要调整tableView的y和height才能显示正常

    //系统默认,tableView.frame = CGRectMake(0,0,self.view.width,self.view.height);
    self.navigationController.navigationBar.translucent = YES;
    self.extendedLayoutIncludesOpaqueBars = NO;
    self.automaticallyAdjustsScrollViewInsets = YES;

    //1.需设置tableView.frame = CGRectMake(0,64,self.view.width,self.view.height - 64);
    //  或设置self.tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
    self.navigationController.navigationBar.translucent = YES;
    self.extendedLayoutIncludesOpaqueBars = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;

    //2.需设置tableView.frame = CGRectMake(0,0,self.view.width,self.view.height - 64);
    self.navigationController.navigationBar.translucent = NO;
    self.extendedLayoutIncludesOpaqueBars = NO;
    self.automaticallyAdjustsScrollViewInsets = YES;

    //3.布局同系统默认,只是没半透明效果
    self.navigationController.navigationBar.translucent = NO;
    self.extendedLayoutIncludesOpaqueBars = YES;
    self.automaticallyAdjustsScrollViewInsets = YES;

    //4.布局同第1点,只是没半透明效果
    self.navigationController.navigationBar.translucent = NO;
    self.extendedLayoutIncludesOpaqueBars = YES;
    self.automaticallyAdjustsScrollViewInsets = NO;

    //5.需设置tableView.frame = CGRectMake(0,0,self.view.width,self.view.height - 64);
    self.navigationController.navigationBar.translucent = NO;
    self.extendedLayoutIncludesOpaqueBars = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;

当你APP里的navigationBar.translucent使用默认值YES时,这时候推荐方案是
系统>1>3>4>2>5
当你APP全局设置navigationBar.translucent为NO时,这时候推荐方案是
3>2>5>4>系统>1

navigationBar.translucent要优先考虑,主要是因为它会影响整个navigationViewController的ViewControllers,当然也可以在viewWillDisappear里改回去,不过还是不推荐。

发表评论

电子邮件地址不会被公开。 必填项已用*标注