美文网首页工具相关
edgesForExtendedLayout

edgesForExtendedLayout

作者: thinkq | 来源:发表于2017-07-08 02:50 被阅读372次

明确一下以前一知半解的属性吧,文中所有的代码都默认写在UIViewController中,所以self特指控制器。
阅读时注意“bar的低下”和“bar的bottom处”两种说法的区别(bar的低下是指层级关系,bar的bottom处是指frame中的位置关系)。

edgesForExtendedLayout

在IOS7以后 ViewController 开始使用全屏布局的,默认控制器内self.view是从屏幕最顶部左上角开始布局,并且不论是当前控制器是否嵌入在UINavigationController还是UITabBarController内,self.view默认占满整个屏幕,edgesForExtendedLayout的默认值为UIRectEdgeAll
如下图设置橙色视图为self.view,绿色视图加在self.view上,设置frame=self.view.bounds,所以两个视图都从屏幕最顶端开始布局,如果底部有tabbar(即UINavigationController还是嵌套在UITabBarController)self.view依然会延伸到屏幕的最底部

UIRectEdgeAll.png

由于上图会导致绿色视图被导航栏遮挡,我们想从导航栏的bottom处开始布局而还坚持想设置绿色视图的frame=self.view.bounds(因为自己写frame=CGRectMake()着实不爽),就可以设置控制器的edgesForExtendedLayout属性为UIRectEdgeNone,这样self.view就会从导航栏的botttom处开始布局:

UIRectEdgeNone.png
  • 哦,还有没说到的点是此属性仅适用于查看嵌入在容器(如UINavigationController)中的控制器。 窗口的根视图控制器不对此属性做出反应。
    edgesForExtendedLayout是UIRectEdge枚举类型:
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
    UIRectEdgeNone   = 0,
    UIRectEdgeTop    = 1 << 0,
    UIRectEdgeLeft   = 1 << 1,
    UIRectEdgeBottom = 1 << 2,
    UIRectEdgeRight  = 1 << 3,
    UIRectEdgeAll    = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} NS_ENUM_AVAILABLE_IOS(7_0);

可以自己尝试在控制器中分别设置看一下效果。

automaticallyAdjustsScrollViewInsets

下图层次结构为self.view->greenView->redView,设置self.edgesForExtendedLayout = UIRectEdgeAll(占满整个屏幕)
第一张图的greenView为UIScrollView对象,第二张图的greenView为UIView,观察greenView的子视图redView的布局位置


greenView为UIScrollView
greenView为UIView.png

当greenView为UIScrollView对象的时候redView从navigationBar的bottom处开始布局,这是因为控制器的automaticallyAdjustsScrollViewInsets属性默认为YES,

automaticallyAdjustsScrollViewInsets是一个布尔值,指示视图控制器是否应自动调整滚动视图的contentInset属性。以解决状态栏,搜索栏,导航栏,工具栏或选项卡栏所消耗的屏幕区域。 给contentInset属性中的上,左,下,右设置值,以避免滚动视图中的子视图被导航条,tabbar等遮挡住。
例如上图打印greenView的contentInset如下:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    NSLog(@"%f-%f-%f-%f",self.greenView.contentInset.top,self.greenView.contentInset.left,self.greenView.contentInset.bottom,self.greenView.contentInset.right);
}

// 打印结果
2017-07-08 01:38:49.163 ZQNavigationBar[12648:786288] 64.000000-0.000000-0.000000-0.000000

greenView.contentInset.top被设置为了64,正好从导航栏bottom处开始布局,避免遮盖。
当设置self.automaticallyAdjustsScrollViewInsets = NO;时,greenView.contentInset将不会被自动设值,redView将从屏幕顶部开始布局

translucent

文档翻译如下:
指示导航栏是否为半透明(YES)的布尔值(否)。
默认值为YES。 如果导航栏具有自定义背景图像,则如果图像的任何像素的alpha值小于1.0,则默认值为YES,否则为否。
如果您在带有不透明的自定义背景图片的导航栏上将此属性设置为YES,则导航栏会将不足1.0的系统定义的不透明度应用于图像。
如果您在带有半透明自定义背景图片的导航栏上将此属性设置为NO,则如果导航栏具有UIBarStyleBlack样式,则导航栏将使用黑色为图像提供不透明的背景,如果导航栏具有UIBarStyleDefault,则为白色,或者导航栏的 barTintColor如果定义了自定义值。

可见关于导航条半透明,设置背景图片这一块幺蛾子甚多,慎重起见将另起文章进行研究,下图侧面证明了设置到导航条视觉效果设置的复杂性

下图层次结构为self.view->greenView->redView,都为UIView(避免受automaticallyAdjustsScrollViewInsets的干扰)

translucent为YES.png translucent为NO.png

由图可见,设置self.navigationController.navigationBar.translucent = NO;时,不但导航条设置为不透明的了而且影响了self.view的布局开始位置(变成从导航条的bottom出开始布局了),导航条不透明了,导航条低下有什么颜色用户都看不到不能再提升视觉效果,干脆改变一下self.view的布局开始位置,方便开发人员——我猜猜的苹果爸爸的意图。实际上这里也可以控制self.view的布局从屏幕最顶部开始布局,如下图:

导航条不透明,self.view依然从屏幕顶部开始布局.png

导航条不透明,self.view依然从屏幕顶部开始布局。HOW???
刚刚学过了设置self.edgesForExtendedLayout = UIRectEdgeAll;可以让self.view占满整个屏幕,难道是这个吗?试一下,结果可见本文第二张图——并没有什么卵用,当设置self.navigationController.navigationBar.translucent = NO;时就要用到了extendedLayoutIncludesOpaqueBars属性

extendedLayoutIncludesOpaqueBars

文档:
一个布尔值,指示扩展布局是否包括不透明的条。
此属性的默认值为NO。
即:设置self.view的布局是否包含设置为不透明之后的导航条,tabbar之类的bar,如果设置了YES,依然会延伸到这些bar的下面,占满整个屏幕,如果设置NO就会避开这些bar,不会延伸到它们下面。上边的考虑是在self.edgesForExtendedLayout = UIRectEdgeAll;的基础之上,如果设置

// 扩展布局包括不透明的条
self.extendedLayoutIncludesOpaqueBars = YES;
// 导航条不透明
self.navigationController.navigationBar.translucent = NO;

然后设置

self.edgesForExtendedLayout = UIRectEdgeNone;

呢?结果:


最后一个图了.png

布局从导航条的botttom处开始!

结论(关于以上四个属性的py交易):

self.navigationController.navigationBar.translucent = YES;(导航条半透明)时,布局的扩展边界,从哪里开始布局受self.edgesForExtendedLayout属性的影响,

  • 当self.edgesForExtendedLayout = UIRectEdgeNone;时self.view会避开一切系统的bar,不会占满整个屏幕
  • 当self.edgesForExtendedLayout = UIRectEdgeAll;时,self.view会延伸到系统bar下面,占满整个屏幕,由于bar半透明可以隐约看到self.view或者其子视图的颜色透上来


self.navigationController.navigationBar.translucent = NO;(导航条不透明)时,self.view是否占满屏幕受到两个属性的影响:self.edgesForExtendedLayout和self.extendedLayoutIncludesOpaqueBars

  • 只有两个同时满足时才会占满整个屏幕(self.extendedLayoutIncludesOpaqueBars = YES && self.edgesForExtendedLayout = UIRectEdgeAll;)

至于
automaticallyAdjustsScrollViewInsets的目的是为了避免系统bar遮挡了要显示的view,所以设置为YES时也只在self.view延伸到bar下面的时候并且子视图里有滚动视图的时候才有用,系统可以把滚动视图contentInset某一个值设置为bar的高度一致(自行学习contentInset属性),相当于对滚动进行了填充避免被遮挡要显示的内容。

最后总结的不太好,请自行结合前文的说明理解。本文举例说的bar都是用的navigationBar,结合文档来看,这几个属性对于系统提供的tabbar等也有相同的效果。

老人新手,如有说的不对之处,万望指正!

相关文章

网友评论

    本文标题:edgesForExtendedLayout

    本文链接:https://www.haomeiwen.com/subject/fycdhxtx.html