在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(安全区)特性。本文的目的就是对他们进行概括和介绍。
本文分为以下几个部分。
这些都是具有安全区属性和方法的类。
可以在Github中找到示例代码,阅读本文时可以同步运行。
在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 X在纵向时有上、下的safe area缩进,而在横向时有左、右、下的缩进。
看一下示例中的情况,我们在一个控制器的view中添加了两个子视图,它们分别包含一个label和一段特定的高度,然后,让他们抵住了view的顶部和底部,也都贴到了view的边缘。
我们看到子视图的内容和顶部的刘海、底部的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
看起来好点了。此外还可以在子视图的类里直接设置子视图上的孙视图的位置,将孙视图放在子视图的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放在安全区,还可以在任意一层子视图结构中,将view放在其父控件的安全区。这样一来,我们可以在保证文本不被刘海和home指示器遮挡的情况下,还能自定义安全区外部分的颜色或者图片背景。
在iOS 11,UIViewController有了一个新属性(额外的安全区缩进):
@available(iOS 11.0, *)
open var additionalSafeAreaInsets: UIEdgeInsets
当ViewController包含其他嵌入的子ViewController时,将使用这个属性。比如说苹果会在UINavigationController和UITabBarController中当它们各自的bar为半透明时使用这个属性。
效果还不错,但是当状态栏隐藏时,奇怪的事情发生了。
其他安全区的缩进尺寸都在预料中,但是导航栏向上移动到了刘海下面。这是个棘手的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的模拟器时,测试你的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
在控制器上添加一个带label的scroll view,并且将其设置为贴着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内容永远不适配,很好理解。
scrollableAxes —— 只对可滚动的方向上适配。比如说当scroll view的content size高度大于frame.size的高度或者启用了alwaysBounceVertical属性时,纵向可滑动;类似的当content size宽度大于frame.size的宽度或者启用了alwaysBounceHorizontal属性时,横向可滑动。
水平模式下只有底部content inset会适配,左侧和右侧content inset不会适配,因为此时横向不能滑动。
always —— 不管是否可滑动,scroll view的content insets永远适配。
automatic —— 是默认项,也是最有意思的。当它满足下列情况时,它和always 一样:
在其他情况下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将会拥有相同的顶部和底部缩进。
在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)
在控制器上添加一个带有自定义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做一个同样的列表:
在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的话,还有专门的讲解(我不用):
也可以看一下我为这篇文章专门写的示例代码:
示例代码
如果有什么问题欢迎留言,谢谢观看!
原文地址
HarmonyOS开发者创新大赛,邀您一起打造智慧生活!
02-01
立即报名参加HarmonyOS开发者创新大赛,赢取150W奖金! 通过学习HarmonyOS,创造性开发出具有全新体验、全新交互的跨终端应用,共同推进HarmonyOS生态建设,打造全场景智慧生活!
iOS 11 safeArea详解及iphoneX 适配
01-05
最近看了许多iPhone X适配的文章,发现很少有介绍safeArea的,就来随便写写 现在对于iPhone X的适配,有一种常见的做法是给导航栏或tabbar增加一个固定的距离,比如顶部增加44pt
IPad Pro 12.9英寸版本的界面适配
懵懵懂懂
8759
IOS开发怎么样适配12.9英寸的Pad Pro12.9英寸的iPad pro,宽高是(1366*1024),Pad其他版本都是(1024*768),按普通尺寸开发的pad应用,最后需要兼容一下pro。为此我自己写了三个宏。应该写在公共文件中#define FULL_SCREEN_RECT CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.widt
iOS开发-iPhoneX的适配-iPhoneX屏幕适配分享
伪随机的张三
1万+
iOS 11正式发布,原本bate版就很多坑,现在还没解决就正式发布了~内心也是酸爽的。除了代码上的坑,更恶劣的就是新的iPhone咯,看到iPhone8和8P的时候内心还算不错的,不过iPhone X就…
iOS11适配-Safe Area_WakeUpYQ
1-6
Safe area 是iOS11的新特性, 帮助你将视图布局在可访问区域内,不被一些特殊视图覆盖,如:状态栏,导航控制器的导航栏等,尤其是具有顶部头帘和底部横条的iPhone X...
iOS 11 安全区域适配总结_coding_girl的博客
1-25
导语:本文主要是对iOS 11下APP中tableView内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的原因分析、adjustContentInset属性的计算方式、什么...
iOS 获取safeAreaInsets bottom 失败
LeeCSDN77的博客
1620
主要是注意获取时机, 需要在viewWillAppear之后,viewWillLayoutSubviews 方法中获取 安全距离改变时机 这里有一个坑要踩踩了一开始笔者也是在这个坑了踩了很久 还以为苹果搞个安全距离的概念来忽悠我们的 如果我们在ViewController - (void)viewDidLoad来打印self.view.safeAreaInsets会发现始终 显示 self...
IOS11 适配遇到的坑
JefferDevs的专栏
1万+
IOS11正式版马上就要发布了,是时候适配一波了。下面就来说说我适配过程中遇到的坑吧。UITableView:默认开启Self-Sizing 首先要知道Self-Sizing是个什么东东。看官方文档的解释: 大概就是说我们不再需要自己去计算cell的高度了,只要设置好这两个属性,约束好布局,系统会自动计算好cell的高度。IOS11以后,Self-Sizing默认开启,包括
iOS11safeArea详解及iphoneX适配-其它代码类资源
2-1
本篇文章主要介绍了iOS 11 safeArea详解及iphoneX 适配,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 iOS11 safeArea ...
iOS 11.0 iPhone X safeArea适配_iOS学习的博客
2-4
说明:使用xib创建视图,工程适配8.0以上系统,xib inspector中未勾选Safe Aear Layout Guide选项(iOS 9.0前无Safe Area Layout Guide)。其中粉色为当前viewcontroller...
iOS 11 适配集锦
hou_manager的博客
5945
iOS 11适配 飞机票1.Demo源码地址 2.简书地址安全区域的适配用Xcode 9 创建storyboard或者xib时,最低版本支持iOS 8时会报: Safe Area Layout Guide before iOS 9.0 如图:原因:在iOS7中引入的Top Layout Guide和Bottom Layout Guide,这些布局指南在iOS 11中被弃用,取而代之的是Safe A
React Native 组件之SafeAreaView
xiangzhihong8的专栏
1万+
SafeAreaView简介 ReactNative官方从0.50.1版本开始,加入了针对iPhone X设备齐刘海页面适配的组件SafeAreaView,为ReactNative开发APP时对iPhone X的页面适配提供了很大的方便。目前,SafeAreaView只适合iOS设备。 SafeAreaView的使用也非常简单,只需要将SafeAreaView嵌套在最根级别的视图中即可,并且在...
iOS开发:iOS11安全区域适配问题_软贱开发攻城狮-CSDN博...
1-24
造成下移原因是iOS 11之后,controller的automaticallyAdjustsScrollViewInsets属性被废弃,导致tableview如果超出安全区域时系统自动调整了SafeAreaInsets值,从而影响了adjusted...
适配iOS11,适配iPhoneX,适配安全区的几个文章和宏_码农...
12-28
#define LL_ViewSafeAreInsets(view) ({UIEdgeInsets insets; if(@available(iOS 11.0, *)) {insets = view.safeAreaInsets;} else {insets = UIEdge...
swift实现类似宏定义功能,举例实现safeAreaInsets
weixin_30632883的博客
113
//注意:要获取safeAreaInsets最好的办法是重写viewSafeAreaInsetsDidChange函数,在里面获取。因为viewDidLoad之前,safeAreaInsets是0值。并且屏幕也会转动。 override func viewSafeAreaInsetsDidChange () { print(view.safeAreaInsets.b...
iPhone X 适配
LiqunZhang的博客
1万+
iPhone X(10)屏幕分辨率与适配,iOS开发适配与UI设计问题。iPhone人机交互指南。 北京时间的9月13日凌晨,美国当地时间的9月12日上午,苹果在发布会上发布了四款产品,本包括全新的Apple Watch Series 3,Apple TV 4K,iPhone 8/8 Plus,和全新iPhone X四款全新产品。其中X是数字10的意思,因此苹果将其读音读作“iPhone Ten
iPhone X 和 iOS 11 适配(Safe Area)_weixin_30500473...
1-18
iPhone X 和 iOS 11 适配(Safe Area) 参考链接: http://www.cocoachina.com/ios/20170921/20623.html https://www.lee1994.com/guan-yu-iphone/...
iOS 11 安全区域适配总结_码农天后的博客_ios 安全区
2-6
导语:本文主要是对iOS 11下APP中tableView内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的原因分析、adjustContentInset属性的计算方式、什么...
《iOS 11 安全区域适配总结》
腾讯Bugly的专栏
3029
本文主要是对iOS 11下企鹅 FM APP中tableView内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的原因分析、adjustContentInset属性的计算方式、什么情况下的tableView会发生内容下移、有哪些解决方法、解决这个问题时遇到的另外一个小问题。
关于iOS中的布局向导(Layout Guide)和安全区域(Safe Area)
Puzhi的专栏
5353
iOS在默认情况下,竖屏会显示状态栏,横屏自动隐藏状态栏。而视图控制器的主视图默认位于屏幕顶端,在竖屏时会被顶部状态栏遮挡。如果我们希望不被状态栏遮挡,则需要先判断横竖屏,然后动态显示隐藏状态栏。如果界面中还存在导航栏、分页栏,情况就更复杂一些。总之,自己处理是一件很麻烦的事情。 布局向导 在iOS 7中,苹果引入了Top Layout Guide(顶部布局向导)和Bottom Layout Gu...
iOS 11 安全区域适配总结_mgr406176009的专栏
1-21
导语:本文主要是对iOS 11下APP中tableView内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的原因分析、adjustContentInset属性的计算方式、什么...
【转】最近很火的 Safe Area 到底是什么
weixin_34082695的博客
136
iOS 7 之后苹果给 UIViewController 引入了 topLayoutGuide 和 bottomLayoutGuide 两个属性来描述不希望被透明的状态栏或者导航栏遮挡的最高位置(status bar, navigation bar, toolbar, tab bar 等)。这个属性的值是一个 length 属性( topLayoutGuide.length)。 这个值可能由当...
iOS开发 关于iPhone X 的适配
wuWu的博客
1万+
1.屏幕尺寸相关变化 高度增加了145pt,变成812pt. 屏幕圆角显示,注意至少留10pt边距。 状态栏高度由20pt变成44pt,留意这个距离就能避开“刘海”的尴尬,相应的导航栏以上变化64->88。 底部工具栏需要为home indicator留出34pt边距。 物理分辨率为1125px * 2436px. 2.横竖屏安全区对比
近很火的 Safe Area 到底是什么
Gabriel的专栏
1286
转自:https://blog.csdn.net/yst19910702/article/details/79260937 iOS 7 之后苹果给 UIViewController 引入了 topLayoutGuide 和 bottomLayoutGuide 两个属性来描述不希望被透明的状态栏或者导航栏遮挡的最高位置(status bar, navigation bar, toolbar, ta...
Xcode9 Safe Area Layout Guide Before iOS9.0报错解决
JackerooChu的博客
2935
9月20日苹果爸爸推送了iOS11.0以及Xcode9,作为开发小白一枚,第一时间更新了Xcode9,去体验一下所谓的跨时代的iPhone X,像往常新建个新项目,结果一运行直接报错(弱弱的说一句,这个xcode9好像并没有那么友好~)然后一Google,苹果爸爸在苹果在iOS7中引入的Top Layout Guide和Bottom Layout Guide,这些布局指南在iOS 11中被弃用,取而
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页