前言
我们在手动设置Frame布局时,经常遇到UITableView
偏移了64px(iPhone上是88px,下面省略说明),这里总结下,有那些情况会出现偏移。
1. navigationBar.translucent
在iOS 7上开始出现的值,意思是navigationBar
是否半透明,默认是YES,当为YES时,打印ViewController.view
和UITableView.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在didLoad
和willAppear
里都出现了变化,这时候我们如果在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
里改回去,不过还是不推荐。