8 area ios safe_ios safe area - CSDN
  • iOS11适配-Safe Area

    2018-04-17 15:23:52
    iOS 7中,苹果介绍了UIViewController中的topLayoutGuide和bottomLayoutGuide这两个属性,用来描述一个不被任何内容遮挡的...在IOS 11,苹果弃用了这些属性而启用safe area。苹果建议我们不要把任何交互放在safe a...

    在iOS 7中,苹果介绍了UIViewController中的topLayoutGuide和bottomLayoutGuide这两个属性,用来描述一个不被任何内容遮挡的屏幕区域,比如说顶部状态栏status bar、导航栏navigation bar、工具栏toolbar、菜单栏tab bar等。在IOS 11,苹果弃用了这些属性而启用safe area。苹果建议我们不要把任何交互放在safe area之外,从iOS 11开始,我们在开发iOS应用的时候,需要进行视图布局时,必须使用新的safe area API。
    当我们做iPhone X适配或者去试着支持safe area时,会发现UIKit中的很多类里都有新的safe area(安全区)特性。本文的目的就是对他们进行概括和介绍。

    目录

    本文分为以下几个部分。

    • UIView
    • UIViewController
    • UIScrollView
    • UITableView
    • UICollectionView

    这些都是具有安全区属性和方法的类。

    示例

    可以在Github中找到示例代码,阅读本文时可以同步运行。

    UIView

    在iOS 11,UIViewController中的UIView的topLayoutGuide和bottomLayoutGuide被替换成了新的安全区属性。

    @available(iOS 11.0, *)
    open var safeAreaInsets: UIEdgeInsets { get }
    
    @available(iOS 11.0, *)
    open var safeAreaLayoutGuide: UILayoutGuide { get }

    safeAreaInsets属性意味着屏幕可以被任何方向遮挡,并不只是上下,当iPhone X出现时,我们就明白了为什么我们需要对左右两边也进行缩进。
    iPhone 8 vs iPhone X safe area (portrait orientation)
    iPhone 8 vs iPhone X safe area (landscape orientation)
    可以看到,iPhone X在纵向时有上、下的safe area缩进,而在横向时有左、右、下的缩进。


    看一下示例中的情况,我们在一个控制器的view中添加了两个子视图,它们分别包含一个label和一段特定的高度,然后,让他们抵住了view的顶部和底部,也都贴到了view的边缘。
    Subviews are attached to the view’s edges
    我们看到子视图的内容和顶部的刘海、底部的home指示器重叠了。要正确布局子视图的位置,我们可以使用手动布局将它们附加到safe area。

    topSubview.frame.origin.x = view.safeAreaInsets.left
    topSubview.frame.origin.y = view.safeAreaInsets.top
    topSubview.frame.size.width = view.bounds.width - view.safeAreaInsets.left - view.safeAreaInsets.right
    topSubview.frame.size.height = 300

    或者使用自动布局

    bottomSubview.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
    bottomSubview.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
    bottomSubview.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    bottomSubview.heightAnchor.constraint(equalToConstant: 300).isActive = true

    Subviews are attached to the superview safe area
    看起来好点了。此外还可以在子视图的类里直接设置子视图上的孙视图的位置,将孙视图放在子视图的safe area里。

    label.frame = safeAreaLayoutGuide.layoutFrame

    或者使用自动布局

    label.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor).isActive = true
    label.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor).isActive = true
    label.leftAnchor.constraint(equalTo: safeAreaLayoutGuide.leftAnchor).isActive = true
    label.rightAnchor.constraint(equalTo: safeAreaLayoutGuide.rightAnchor).isActive = true

    子视图填满了view,而label放在了它的父视图的安全区
    这下就厉害了,我们不仅在控制器里可以将view放在安全区,还可以在任意一层子视图结构中,将view放在其父控件的安全区。这样一来,我们可以在保证文本不被刘海和home指示器遮挡的情况下,还能自定义安全区外部分的颜色或者图片背景。

    UIViewController

    在iOS 11,UIViewController有了一个新属性(额外的安全区缩进):

    @available(iOS 11.0, *)
    open var additionalSafeAreaInsets: UIEdgeInsets

    当ViewController包含其他嵌入的子ViewController时,将使用这个属性。比如说苹果会在UINavigationController和UITabBarController中当它们各自的bar为半透明时使用这个属性。
    导航栏和菜单栏为半透明时的安全区。view的子视图贴在view的边缘,label在子视图的安全区
    效果还不错,但是当状态栏隐藏时,奇怪的事情发生了。
    导航栏和菜单栏为半透明而且状态栏为隐藏时的安全区。view的子视图贴在view的边缘,label在子视图的安全区
    其他安全区的缩进尺寸都在预料中,但是导航栏向上移动到了刘海下面。这是个棘手的bug,而且除了在Stack Overflow上找到的一个还好的方法之外,目前没找到更好的方法去解决。
    当我们修改additional safe area insets属性或者safe area insets被系统修改时,我们可以通过UIViewController或者UIView中特定的方法来监听。

    // UIView
    @available(iOS 11.0, *)
    open func safeAreaInsetsDidChange()
    
    //UIViewController
    @available(iOS 11.0, *)
    open func viewSafeAreaInsetsDidChange()

    模拟iPhone X的安全区

    额外的安全区缩进也可以用于,当你没有iPhone X真机或者不方便用iPhone X的模拟器时,测试你的app是否支持iPhone X。比如像示例代码里一样,通过实时修改缩进值,观察安全区的变化。

    //portrait orientation, status bar is shown
    additionalSafeAreaInsets.top = 24.0
    additionalSafeAreaInsets.bottom = 34.0
    
    //portrait orientation, status bar is hidden
    additionalSafeAreaInsets.top = 44.0
    additionalSafeAreaInsets.bottom = 34.0
    
    //landscape orientation
    additionalSafeAreaInsets.left = 44.0
    additionalSafeAreaInsets.bottom = 21.0
    additionalSafeAreaInsets.right = 44.0

    模拟iPhone X上的安全区缩进

    UIScrollView

    在控制器上添加一个带label的scroll view,并且将其设置为贴着view边缘。
    scrollView贴着view边缘
    我们可以看到scroll view的缩进在顶部和底部自动适配了。在iOS 7及更高版本的系统,scroll view的内容缩进可以用UIViewController’s中的automaticallyAdjustsScrollViewInsets属性进行适配;但是在iOS 11中,这个属性被弃用了,取而代之的是UIScrollView中的一个新属性contentInsetAdjustmentBehavior。

    @available(iOS 11.0, *)
    public enum UIScrollViewContentInsetAdjustmentBehavior : Int {    
        case automatic          //default value
        case scrollableAxes
        case never
        case always
    }
    
    @available(iOS 11.0, *)
    open var contentInsetAdjustmentBehavior: UIScrollViewContentInsetAdjustmentBehavior

    Content Insets Adjustment Behavior

    never —— scroll view内容永远不适配,很好理解。
     scroll view贴在view的边缘(contentInsetAdjustmentBehavior == .never)
    scrollableAxes —— 只对可滚动的方向上适配。比如说当scroll view的content size高度大于frame.size的高度或者启用了alwaysBounceVertical属性时,纵向可滑动;类似的当content size宽度大于frame.size的宽度或者启用了alwaysBounceHorizontal属性时,横向可滑动。
     scroll view贴在view的边缘(contentInsetAdjustmentBehavior == .scrollableAxes)。纵向可滚动
    水平模式下只有底部content inset会适配,左侧和右侧content inset不会适配,因为此时横向不能滑动。
    always —— 不管是否可滑动,scroll view的content insets永远适配。
    scroll view贴在view的边缘(contentInsetAdjustmentBehavior == .always)。纵向可滚动
    automatic —— 是默认项,也是最有意思的。当它满足下列情况时,它和always 一样:

    • scroll view横向可滑动,纵向不可滑动
    • scroll view是控制器view的最底层子视图
    • 控制器是navigation控制器或tabBar控制器的子控制器
    • automaticallyAdjustsScrollViewInsets为真

    在其他情况下automatic相当于scrollableAxes
    关于automatic选项的更多描述,可以查看UIScrollView类:

    类似于.scrollableAxes,但是考虑到向下兼容,当scroll view位于navigation controller中且设定了automaticallyAdjustsScrollViewInsets为真时,也会自动调整顶部和底部的contentInset,不管scroll view是否可滑动。

    然而xcode苹果文档中的描述略有不同

    当一个控制器展示在一个navigation控制器或者tabBar控制器时,其中的scroll view总是会被自动调整。如果scroll view处于横向可滑动,那么当未设置安全区indest的时候,横向的content offset也会自动调整。
    因为考虑到向下兼容,automatic项被设置为默认。也就是说,在 iOS 10和 iOS 11中,横向可滑动的scroll view将会拥有相同的顶部和底部缩进。

    Adjusted Content Insets

    在iOS 11中,UIScrollView拥有了一个新的属性——adjustedContentInset:

    @available(iOS 11.0, *)
    open var adjustedContentInset: UIEdgeInsets { get }

    那么contentInset和adjustedContentInset属性有什么不同?我们打印一下当scroll view被导航栏和菜单栏遮挡时两者的值:

    //iOS 10
    //contentInset = UIEdgeInsets(top: 64.0, left: 0.0, bottom: 49.0, right: 0.0)
    //iOS 11
    //contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
    //adjustedContentInset = UIEdgeInsets(top: 64.0, left: 0.0, bottom: 49.0, right: 0.0)

    现在我们给contentInset从四个方向分别加10个点,然后再打印一下:

    //iOS 10
    //contentInset = UIEdgeInsets(top: 74.0, left: 10.0, bottom: 59.0, right: 10.0)
    //iOS 11
    //contentInset = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
    //adjustedContentInset = UIEdgeInsets(top: 74.0, left: 10.0, bottom: 59.0, right: 10.0)

    我们可以看到在iOS 11中,scroll view实际的content insets将从adjustedContentInset属性中取得,而不再是contentInset属性。意思是当app需要同时支持iOS 10和 iOS 11时,我们需要为content insets的适配写两套不同的逻辑。
    想要监听contentInset的值被修改的情况,UIScrollView和UIScrollViewDelegate提供了响应的方法。

    //UIScrollView
    @available(iOS 11.0, *)
    open func adjustedContentInsetDidChange()
    
    //UIScrollViewDelegate
    @available(iOS 11.0, *)
    optional public func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView)

    UITableView

    在控制器上添加一个带有自定义header和自定义cell的table view。

    自定义的header上有一个label。自定义的cell也有一个label,带一个分割线。header和cell是透明的,cell的content view背景为白色,header的content view背景为红色。
    我们可以看到,当横屏时,header和cell的content view frame变了,但是同时cell以及分割线的frame没有变。这是个默认项,我们可以用UITableView的新属性insetsContentViewsToSafeArea来进行控制。

    @available(iOS 11.0, *)
    open var insetsContentViewsToSafeArea: Bool

    如果将此属性设置为NO:

    我们可以看到现在header、footer、cell的content views frame就等于他们各自的frame。
    这就意味着在iOS 11,我们在为header、footer、cell添加子控件时,不需要改变子控件的位置,UITableView自动帮我们适配。

    UICollectionView

    我们再试着在UICollectionView做一个同样的列表:

    在collection view中使用了UICollectionViewFlowLayout,滑动方向设为纵向,cell是透明的,cell的content view背景设为白色,header也就是UICollectionReusableView没有contentView,我们把它的背景设为红色。
    从截图中可以看到,collection view在默认情况下没有缩进header、footer和cell的内容。想要正确布局它的内容,唯一的方法是把子视图放到安全区:

    好,现在改变cell的size,使我们的collection view显示网格:

    可以看到在横屏时cell被刘海遮挡了一部分。想要解决这个问题我们需要在section的content insets上添加安全区,但是其实在iOS 11中UICollectionViewFlowLayout有了一个新属性sectionInsetReference用来处理它。

    @available(iOS 11.0, *)
    public enum UICollectionViewFlowLayoutSectionInsetReference : Int {    
        case fromContentInset        //default value
        case fromSafeArea
        case fromLayoutMargins
    }
    
    @available(iOS 11.0, *)
    open var sectionInsetReference: UICollectionViewFlowLayoutSectionInsetReference

    想做出我们想要的效果只需要设置成fromSafeArea。这个时候section的实际 content insets就等于content insets加上安全区insets。

    类似地,当使用fromLayoutMargins时,collection view就在content insets基础上加了margins。

    总结

    在iOS 11中,苹果为我们加了很多实用的工具来使用安全区。在这篇文章我试着把他们全部介绍了一遍。希望本文可以帮助大家更好地在app中应用安全区。另外,我建议大家看一下相关的WWDC视频或者阅读相关文章:

    如果使用storyboards的话,还有专门的讲解(我不用):

    也可以看一下我为这篇文章专门写的示例代码:
    示例代码

    如果有什么问题欢迎留言,谢谢观看!

    原文地址

    展开全文
  • 差Xcode这么不给面子,看了下错误信息“Safe Area Layout Guide before iOS 9.0”,“Safe Area”, 记得WWCD上面老库克提到过对于iPhone X的适配苹果提供了一个安全区域的概念,我的Xcode工程最低支持版本是7.0,所

    iPhoneX马上快要预售了,齐刘海的小发型还是够屌屌的。今天升级完Xcode9, 打开Xcode顺手编译的了一下工程结果报错了!差Xcode这么不给面子,看了下错误信息“Safe Area Layout Guide before iOS 9.0”,“Safe Area”, 记得WWCD上面老库克提到过对于iPhone X的适配苹果提供了一个安全区域的概念,我的Xcode工程最低支持版本是7.0,所以编译报错。

    这里写图片描述

    看了一下ViewController中确实多了一个像状态栏的View,这个应该就是刘海的部分了,如图:

    这里写图片描述

    然后这个问题解决确实很简单的:选中Storyboard,查看“Show the File inspector”, 属性面板中默认勾选了”Usa SafeArea Layout Guides” 的选项,去掉它就可以解决问题了。

    这里写图片描述

    最后如果工程中有 LaunchScreen.storyboard 的同学不要忘记去除launchScreen面板中的 “Usa SafeArea Layout Guides” 的选项。
    这里写图片描述

    展开全文
  • [iOS]Masonry适配SafeArea

    2019-01-27 22:06:34
    SafeArea:翻译中文语义即为安全区域,大家应该都不陌生,它是在iOS11引入的一个概念,在iPhoneX 等刘海屏出来之前,开发者如果想在一个ViewController的view上面添加子控件,只需要考虑我们想要添加的子控件距离屏幕...

    一、什么是SafeArea

    SafeArea:翻译中文语义即为安全区域,大家应该都不陌生,它是在iOS11引入的一个概念,在iPhoneX 等刘海屏出来之前,开发者如果想在一个ViewController的view上面添加子控件,只需要考虑我们想要添加的子控件距离屏幕上、下的边界。也就是在iOS7当中引入的两个属性:topLayoutGuide和bottomLayoutGuide。如果ViewController是被包裹在NavigationController或者SatusBar是可见的情况下,这两个属性就是分别表示子控件不被导航栏或状态栏挡住的区域。

    在Apple发布了iPhoneX之后,针对横竖屏我们发现仅仅依靠上面两个属性是不能满足视图的布局的。在竖屏情况下,我们要针对上边的刘海和底部的Home Indicator做适配。在横屏的情况下我们要考虑左、右边(刘海)和底部(Home Indicator)的适配。苹果为了方便开发者做这方面的适配,特别针对UIView引入了safeAreaLayoutGuide属性。API对它的解释是:The layout guide representing the portion of your view that is unobscured by bars and other content.也就是说它是一个布局指南,这个布局指南使得我们对view的布局不受一些bar或者其他内容的遮挡。我们可以这么理解:所谓的安全区域就是safeAraeLayoutGuide这个虚拟的view所显示的区域,所有子控件只要是在这个虚拟的view之内都可以被完整的显示出来。

     

    二、针对safeAreaLayoutGuide布局

     

    我们考虑一下这个场景:在一个ViewController中的view上,我们想要放一个label,并且通过布局使之frame完全与view重合。在iOS11之前,我们写这个label的布局代码只需要针对这个view来写就可以了。但是现在情况可能不一样了,如果现在还是针对view来做的话,就会有可能导致我们添加的子控件的内容超出safeArea的范围。

    下面,我们来看看在iOS11中是如何写布局的:

    [self.view addSubview:self.lable];
        
    self.lable.translatesAutoresizingMaskIntoConstraints = NO;
    UILayoutGuide *safeGuide = self.view.safeAreaLayoutGuide;
    NSLog(@"safeGuide.frame--->%@",NSStringFromCGRect(safeGuide.layoutFrame));
        
    NSLayoutConstraint *topCon = [self.lable.topAnchor constraintEqualToAnchor:safeGuide.topAnchor];
    NSLayoutConstraint *bottomCon = [self.lable.bottomAnchor constraintEqualToAnchor:safeGuide.bottomAnchor];
    NSLayoutConstraint *leftCon = [self.lable.leftAnchor constraintEqualToAnchor:safeGuide.leftAnchor constant:0];
    NSLayoutConstraint *rightCon = [self.lable.rightAnchor constraintEqualToAnchor:safeGuide.rightAnchor constant:0];
    [NSLayoutConstraint activateConstraints:@[topCon, bottomCon, leftCon, rightCon]];

    三、Masonry关于safeArea的布局

    回到本文主题,我们看到如果用Apple的布局语法来写布局,很一件很费劲的事情(至少对于我来说是这样),代码冗长还可读性差。如果习惯了用Masonry布局的,就简单多了,这个库的作者专门针对safeArea也提供了相关的布局属性。具体的API大家有空上去看,带了mas_safeAreaLayout的都是作者封装好了的属性直接拿来用。目前可以通过这样来写达到上面那个例子的目的。

    [self.view addSubview:self.label3];
    if (@available(iOS 11,*)) {
        [self.label3 mas_makeConstraints:^(MASConstraintMaker *make) {
           make.top.mas_equalTo(self.view.mas_safeAreaLayoutGuideTop);
           make.left.equalTo(self.view.mas_safeAreaLayoutGuideLeft);
           make.right.equalTo(self.view.mas_safeAreaLayoutGuideRight);
           make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
        }];
     } else {
        make.edge.offset(0);
     }

    使用Masonry有一个小技巧,我们平时在写控件布局的时候,不管是什么样的页面,我们都自定义一个ContentView,让这个ContentView针对safeAreaLayoutGuide做好布局,然后我们再在这个ContentView上写其他的子控件,这样做的好处的,不管控件多少或者多复杂,我们肯定能保证它们都可能完美显示。

     

     

     

     

     

     

    展开全文
  • 在Xcode9.0环境下,新建xib会报Safe Area Layout Guide before ios9.0 解决: 把Use Safe Area Layout Guides取消打勾。

    在Xcode9.0环境下,新建xib会报Safe Area Layout Guide before ios9.0

    解决:


    把Use Safe Area Layout Guides取消打勾。

    展开全文
  • 问题和解决方案地址送你的独白么我就上面的方法补充一点 创建xib控制器的SafeArea的高度默认是20的 ,那么按照那个方法来弄的话会没有效果,那么怎么修改SafeArea的高度呢?请看下图这样设置一个导航栏之后再按照...


    问题和解决方案地址送你的独白么

    我就上面的方法补充一点

    创建xib控制器的SafeArea的高度默认是20的 ,那么按照那个方法来弄的话会没有效果,那么怎么修改SafeArea的高度呢?请看下图

    这里写图片描述

    这样设置一个导航栏之后再按照上面链接的方法进行设置就好了

    我的github:https://github.com/sjxt 欢迎star一下

    展开全文
  • 在为iphoneX适配时,xib上启用了safeArea的一些选项,但是换到ios9上发现页面嵌在上面了,如图所示:在该controller下设置导航栏为不透明就好了,self.navigationController.navigationBar.translucent = NO;...
  • 使用xcode9 编译报,safe area layout guide before ios 9.0问题 将Deployment Target 设置成9.0以上版本就行了
  • 删除SceneDelegate 参考文章 删除SceneDelegate文件 直接删除即可。 Info.plist Info.plist -> Open As ->...首先,删除 #pragma mark - UISceneSession lifecycle 下的协议方法。...然后,再 ...
  • iOS 11.0之后系统新增安全区域变化方法 1 2 3 4 UIViewController中新增: - (void)viewSafeAreaInsetsDidChange; UIView中新增: - (void)viewSafeAreaInsetsDidChange; ...
  • 取消 use safe Area Layout Guides的勾选
  • 今天创建新工程后将 Target => General => Deployment Info => Main Interface 中...Safe Area Layout Guide before iOS 9.0  根据提示是这次苹果官方迭代更新后出现的异常, iOS 7 中的 Layout Guide 布局在 iO
  • 本文的出发点是对iOS设备的适配, 我们之前的适配只是考虑设备的尺寸, 设备的方向, 而在iPhoneX出来之后呢, 我们又多了一种考量, 那就是刘海和底部横条(HomeIndicator), 我们通过UIKit11.0之后新增的API来解决这个...
  • Xcode 9.0 新建工程报错 xcode Safe Area Layout Guide Before IOS 9.0 xcode 9更新玩一个最简单的页面看看iPhone X有多丑 ,结果直接报错  Safe Area Layout Guide Before IOS 9.0 xcode 很不给面子 解决如下
  • 关于iOS safe area layout guide before ios 9.0问题的解决 近期升级Xcode为9.0后,测试视频应用代码,Deployment target 从11.0改为8.1, 头文件中增加如下代码, #import @interface ViewController : ...
  • /Users/XXX/XXX/Base.lproj/LaunchScreen.storyboard:6Tk-OE-BBY: error: Safe Area Layout Guide before iOS 9.0。原因:Xcode9中引入新特性Safe Area Layout Guide代替之前的Top、Bottom Lauout Guide。解决方法:...
  • iOS在默认情况下,竖屏会显示状态栏,横屏自动隐藏状态栏。而视图控制器的主视图默认位于屏幕顶端,在竖屏时会被顶部状态栏遮挡。如果我们希望不被状态栏遮挡,则需要先判断横竖屏,然后动态显示隐藏状态栏。如果...
  • safeAreaLayoutGuide

    2019-10-11 19:36:56
    https://www.jianshu.com/p/9d68a220983b Safe Area Layout Guide对应的SafeArea特性使用(DeploymentTarget9.0及后) 解决方案: 1. DeploymentTarget 9.0及后 2. DeploymentTarget 8.0
  • 昨天趁着周末把xcode版本给更到了9.0,今天在工程中新建一个带有xib的View,报错:Safe Area Layout Guide Before IOS 9.0 报错的字面意思就是safe area布局应用在iOS 9之前的版本上了.我们的解决版本可以从两个...
1 2 3 4 5 ... 20
收藏数 1,653
精华内容 661
关键字:

8 area ios safe