1 普通viewController中edgesForExtendedLayout
和Navibar的影响
iOS7开始, ViewController默认会使用全屏布局(full-screen layout). 并且在ViewController
中增加了一些属性来影响VC管理的View的frame.
比如edgesForExtendedLayout
, 它的值是UIExtendedEdge
的属性,指定UIViewController
上的根视图self.view
边缘要延伸的方向,由于iOS7鼓励全屏布局,所以它的默认值是UIRectEdgeAll,四周边缘均延伸,就是说,如果即使视图中上有UINavigationBar,下有UITabBar,那么视图仍会延伸覆盖到四周的区域。它的文档说明如下枚举如下:
/*
Summary
The edges that you extend for your view controller.
Declaration
@property(nonatomic, assign) UIRectEdge edgesForExtendedLayout;
Discussion
Instead of this property, use the safe area of your view to determine which parts of your interface are occluded by other content. For more information, see the safeAreaLayoutGuide and safeAreaInsets properties of UIView.
In iOS 10 and earlier, use this property to report which edges of your view controller extend underneath navigation bars or other system-provided views. The default value of this property is UIRectEdgeAll, and it is recommended that you do not change that value.
If you remove an edge value from this property, the system does not lay out your content underneath other bars on that same edge. In addition, the system provides a default background so that translucent bars have an appropriate appearance. The window’s root view controller does not react to this property.
*/
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
UIRectEdgeNone = 0,
UIRectEdgeTop = 1 << 0,
UIRectEdgeLeft = 1 << 1,
UIRectEdgeBottom = 1 << 2,
UIRectEdgeRight = 1 << 3,
UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} API_AVAILABLE(ios(7.0));
默认情况下vc.edgesForExtendedLayout = UIRectEdgeAll
, 它表示viewController
的view
是从屏幕顶部最左上角开始布局!!!
当这个ViewController
被嵌入到UINavigationController
和UITabBarController
中时, 会受到NavgationController
和TabBarController
的透明度(translucent
)的影响!!!分成以下情况:
-
self.navigationController.navigationBar.translucent = YES;
并且self.tabBarController.tabBar.translucent = YES;
那么vc.edgesForExtendedLayout = UIRectEdgeAll
情况下, view依然会铺满全屏 -
self.navigationController.navigationBar.translucent = NO
时,vc.view
的左上角会从self.navigationController.navigationBar
的左下角开始, 但是self.view.frame == (0, 0, ScreenW, ScreenH - barHeight)
, 也就是从view从导航栏左下角那里开始布局!!! 同理 ``self.tabBarController.tabBar.translucent = NO;`类似
warning:
- 设置
UINavigationBar.barStyle
会影响到translucent
的属性!!! 一定要注意!!!!! 因此, 最好的方法是手动设置barStyle
, 然后指定translucent
的值!!!- 在
UIRectEdgeAll
+navbar.translucent = NO
, 在viewDidLoad
方法中self.view.frame: NSRect: {{0, 0}, {375, 812}}
, 而在viewDidLayoutSubviews
中self.view.frame: NSRect: {{0, 0}, {375, 724}}
在iPhoneX中, 如果使用 UIRectEdgeNone
配置, 那么不论self.navigationController.navigationBar.translucent
为YES
或者NO
, 在viewDidLoad
中self.view.frame: NSRect: {{0, 0}, {375, 812}}
, 咋那么在viewDidLayoutSubviews
中self.view.frame: NSRect: {{0, 88}, {375, 724}}
会体现差别!!!请注意view.frame
最终的origin
和height
automaticallyAdjustsScrollViewInsets
注意这个属性不会影响view.frame
!!!!它会影响scrollview
(self.view上第一个view)的contentInset
!!!
当你的view是UIScrollerView
或其子类(UITableView)时, 这个属性就派上用场了. 如果我们想让table从navbar的底部开始, 同事又希望滚动时, tbale延伸到整个view界面!!!(behind the navigation bar). 如果用edgesForExtendedLayout
, 滚动时无法满足要求, 因为table始终从navigation bar
的底部开始!!! 滚动时不会 behind it.
automaticallyAdjustsScrollViewInsets
就能很好地满足需求,设置些属性值为YES(也是默认值),viewController
会在table
顶部添加inset
,所以table的内容会出现在navigation bar
的底部。但是滚动时又能覆盖整个屏幕(table.frame是全屏)
automaticallyAdjustsScrollViewInsets=NO
时, 系统不会增加inset
!!!
无论是YES or NO,滚支时table都是覆盖整个屏幕的,但是YES时,因为增加 inset的原因导致 table
的内容不会被navigation bar
挡住。
从苹果的官方文档可知,不只是navigation bar
,status bar
, search bar
, toolbar
or tab bar
都有类似的效果, 也就是修改tableview
的inset
extendedLayoutIncludesOpaqueBars
vc
还有一个关键属性: extendedLayoutIncludesOpaqueBars
, 表示不透明的bar下面是否可以扩展(default == NO, 也就是不扩展). 即导航栏UINavigationbar不透明的时, 默认不能扩展!!!
这个属性是对前面两个属性的补充!!! 如果navbar
是不透明的, view
不会被延伸到navbar
底部!!!除非xtendedLayoutIncludesOpaqueBars = YES;
如果想要让你的view延伸到navigation bar
(edgesForExtendedLayout to UIRectEdgeAll)并且设置此属性为NO(默认)。view就不会延伸到不透明的status bar。
其他总结
想要为UINavigationBar设置某个色值的纯色背景,则
- translucent属性为YES:
- 如果想要通过视觉大大一丝不苟的像素眼,请参照
https://www.jianshu.com/p/6a5552ec5099
方案2:利用别的视图遮蔽掉这些透明控件 - 否则若只是要求肉眼不容易发觉(请不要吐槽我的随便),请利用 barTintColor属性
- 如果要求放松到无所谓的程度,透不透视都不关心,请使用 setBackgroundImage:forBarMetrics: 方法或者干脆用 backgroundColor属性
- translucent属性为NO:
- 如果想要通过视觉大大一丝不苟的像素眼,依旧参照
https://www.jianshu.com/p/6a5552ec5099
方案2:利用别的视图遮蔽掉这些透明控件 - 否则若只是要求肉眼不容易发觉(请不要吐槽我的随便),使用barTintColor 或者 setBackgroundImage:forBarMetrics: 方法(仍然存在混色问题,例如设置纯红色,view hierarchy看单个视图取色为0xff0000,而直接从App中取色则前者效果为0xfb2930,后者效果为0xfc0d1b,相对而言后者更精准)
注意: backgroundColor 设置则是无效的,请放弃该方式
参考
https://www.jianshu.com/p/ca3c5a94c32b
https://www.cnblogs.com/helmsyy/p/8880835.html
https://www.jianshu.com/p/6a5552ec5099