美文网首页Swift_LearniOS10以后的新技术
iOS safeAreaInsets安全区域相关知识

iOS safeAreaInsets安全区域相关知识

作者: 爱思考的阿喵 | 来源:发表于2019-07-02 15:02 被阅读0次

    iOS11 系统发布后,UIView多了几个与安全区域相关的属性和方法,用于界面适配,如:safeAreaInsets、safeAreaLayoutGuide、insetsLayoutMarginsFromSafeArea,以及safeAreaInsetsDidChange方法,初看到这些时我眼花缭乱,不知其存在的意义何在.扪参历井仰胁息,以手抚膺坐长叹.这特么到底怎么用啊???经过不懈的努力,阅读开发文档、测试,我明了了.

    以下是我的理解.

    在iOS11前的系统,做界面适配时,如果界面上有导航栏时,想做到界面不被导航栏遮盖住,需要将控件的frame.origin.y值加上导航栏和状态栏的高度,也就是frame.origin.y-64.当iPhoneX系列没发布前,其他所有iPhone机型的导航栏、状态栏、tab栏,高度都一样,做适配时很简单.但是iPhoneX系列发布后,出现了新的状态栏、tab栏高度,导致适配工作量加大.所以官方新增了safeAreaInsets等属性,方便界面适配.

    safeAreaInsets

    safeArea是指没有被navigation bars, tab bars, toolbars,或其他视图控制器遮盖的区域,通过safeAreaInsets可以获取到视图的安全距离.但是如果一个view没有在视图层次结构中或未在屏幕上显示,则safeAreaInsets为0.

    对于一个VC的root view,safeArea指的是未被状态栏、一些可见的bars、和通过additionalSafeAreaInsets属性设置的值遮盖的区域,(注意下面iPhoneX的安全区域)


    VC的rootView的safeArea.png

    对于在视图层次结构中的其他视图,safeArea指的是未被navigation bars, tab bars, toolbars,或其他视图控制器遮盖的区域;例如如果一个视图的完全在它父视图的范围内,那么safeAreaInsets为0;如果其超出父视图的安全范围,那么safeAreaInsets按照被遮住的大小计算.例如:
    下面是一个vc, vc的rootView是redView,redView有个subView是yellowView,当yellowView不处于redView的安全区域之内时:


    yellowView not in redView's safeArea

    yellowView.safeAreaInsets=UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    redView.safeAreaInsets=UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

    当yellowView处在redView的安全区域内时:


    image.png

    yellowView.safeAreaInsets=UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
    redView.safeAreaInsets=UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

    如果对系统所提供的安全区域不满意,还可以通过additionalSafeAreaInsets属性来修改安全区域,例如设置 vc.additionalSafeAreaInsets = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0),相应的
    redView.safeAreaInsets=UIEdgeInsets(top: 52.0, left: 8.0, bottom: 42.0, right: 8.0)

    说白了safeAreaInsets 指的就是一个控件可见区域距离屏幕上下左右边的距离.

    那么在做适配时,这个属性怎么用呢?
    一个vc从创建到界面显示,会依次调用以下方法:
    viewDidLoad ->viewWillAppear->viewSafeAreaInsetsDidChange->viewWillLayoutSubviews->viewDidLayoutSubviews->viewDidAppear

    在viewSafeAreaInsetsDidChange 方法时界面的safeAreaInsets值会被计算出来,在这个方法中可以更改控件位置:

    override func viewSafeAreaInsetsDidChange() {
            if #available(iOS 11.0, *) {
                self.yellowView.frame = CGRect.init(x: 0, y: self.view.safeAreaInsets.top, width: self.view.frame.size.width, height: self.view.frame.size.height - self.view.safeAreaInsets.top - self.view.safeAreaInsets.bottom)
            } else {
                // Fallback on earlier versions
            }
        }
    

    safeAreaLayoutGuide

    如果不用硬编码形式设置位置,而是使用autolayout布局,safeAreaLayoutGuide属性会更有用.
    safeAreaLayoutGuide是UILayoutGuide类型,适用于autolayout,而safeAreaInsets是UIEdgeInsets类型,适用于用frame设置位置

     override func viewDidLoad() {
             yellowView.snp.makeConstraints { (make) in
                if #available(iOS 11.0, *) {
                   make.edges.equalTo(self.view.safeAreaLayoutGuide)
                } else {
                    make.edges.equalTo(UIEdgeInsets.zero)
                }
            }
    }
    

    注意: 如果在viewDidLoad不能用make.edges.equalTo(self.view.safeAreaInsets) 设置边距,在viewDidLoad方法中safeAreaInsets为0.

    insetsLayoutMarginsFromSafeArea

    一个布尔值,指示是否自动更新视图的布局边距以反映安全区域,默认为yes.
    单看这个属性,就知道其与layoutMargins、safeAreaInsets属性有关,事实也确实如此.
    iOS中layoutMargins 默认为 UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
    当insetsLayoutMarginsFromSafeArea == true时:
    layoutMargins = layoutMargins + safeAreaInsets;

    例如:
    在vc中更改安全区域大小,并设置yellowView充满全屏:

            if #available(iOS 11.0, *) {
                self.additionalSafeAreaInsets = UIEdgeInsets.init(top: 50, left: 50, bottom: 50, 
                 right: 50)
            } else {
                // Fallback on earlier versions
            }
            yellowView.snp.makeConstraints { (make) in 
                    make.edges.equalTo(UIEdgeInsets.zero)
            }
    

    此时,yellowView未处于redView的安全区域内,此时yellowView.safeAreaInsets=UIEdgeInsets(top:94.0, left: 50.0, bottom: 84.0, right:50.0)
    yellowView.layoutMargins = UIEdgeInsets(top:102.0, left: 58.0, bottom: 92.0, right:58.0)
    在yellowView中添加blueView,blueView的适配如下:

       blueView.snp.makeConstraints { (make) in
                if #available(iOS 9.0, *) {
                    make.edges.equalTo(self.layoutMarginsGuide)
                } else {
                    // Fallback on earlier versions
                }
            }
    
    image.png

    此时blueView.frame = (58 102; 298 702),受到了安全区域的影响;如果想不受到安全区域的影响,只需要设置yellowView.insetsLayoutMarginsFromSafeArea = false 即可

    综上,就是我对安全区域的理解,及如何运用.

    相关文章

      网友评论

        本文标题:iOS safeAreaInsets安全区域相关知识

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