适配 iOS 11 & iPhone X 大全
1.升级iOS11后造成的变化
1. 1升级后,发现某个拥有tableView的界面错乱,组间距和contentInset错乱,因为iOS11中UIViewController的automaticallyAdjustsScrollViewInsets属性被废弃了,因此当tableView超出安全区域时,系统自动会调整SafeAreaInsets值,进而影响adjustedContentInset值
// 有些界面以下使用代理方法来设置,发现并没有生效
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
// 这样的原理是因为之前只是实现了高度的代理方法,却没有实现View的代理方法,iOS10及以前这么写是没问题的,iOS11开启了行高估算机制引起的bug,因此有以下几种解决方法:
// 解决方法一:添加实现View的代理方法,只有实现下面两个方法,方法 (CGFloat)tableView: heightForFooterInSection: 才会生效
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return nil;
}
// 解决方法二:直接使用tableView属性进行设置,修复该UI错乱
self.tableView.sectionHeaderHeight = 0;
self.tableView.sectionFooterHeight = 5;
[_optionTableView setContentInset:UIEdgeInsetsMake(-35, 0, 0, 0)];
// 解决方法三:添加以下代码关闭估算行高
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
1.2 如果使用了Masonry 进行布局,就要适配safeArea
if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) {
make.edges.equalTo(self.view.safeAreaInsets);
} else {
make.edges.equalTo(self.view);
}
1.3 对于IM的发送原图功能,iOS11启动全新的HEIC 格式的图片,iPhone7以上设备+iOS11排出的live照片是".heic"格式图片,同一张live格式的图片,iOS10发送就没问题(转成了jpg),iOS11就不行
微信的处理方式是一比一转化成jpg格式
QQ和钉钉的处理方式是直接压缩,即使是原图也压缩为非原图
微信的逼格太高,没找到现成的方法,我采用的是QQ 的方案
2、使用Xcode9 编译后发现的问题
2.1 发现“fastSocket”第三方报错,具体原因是缺少C99的头文件,引入“#include ”即可

2.2 导航栏的新特性
原生的搜索栏样式发生改变
查看 API 后发现,iOS11后将searchController赋值给了NavigationItem,通过属性hidesSearchBarWhenScrolling可以控制搜索栏是否在滑动的时候进行隐藏和显示
// A view controller that will be shown inside of a navigation controller can assign a UISearchController to this property to display the search controller’s search bar in its containing navigation controller’s navigation bar.
@property (nonatomic, retain, nullable) UISearchController *searchController API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
// If this property is true (the default), the searchController’s search bar will hide as the user scrolls in the top view controller’s scroll view. If false, the search bar will remain visible and pinned underneath the navigation bar.
@property (nonatomic) BOOL hidesSearchBarWhenScrolling API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
另外,UINavigationBar新增属性 BOOL值prefersLargeTitles来实现下面的效果,并可以通过largeTitleTextAttributes来设置大标题的文本样式。设置大标题之后,导航栏的高度就会由之前的64pt变成 96pt,如果项目中有直接写死的高度或者隐藏导航栏之类的操作,就需要适配一下

有个界面使用到了导航栏按钮相关的frame,也发生了UI错乱,查看UI层级关系后发现,iOS11以前是直接把按钮加到了UINavigationBar上面,而iOS11则是先将按钮加到了_UITAMICAdaptorView,再加到_UIButtonBarStackView、_UINavigationBarContentView,接着才是UINavigationBar。因此如果需要获取导航栏按钮 frame 或者 superView,这里需要专门做下适配


3.iPhone X的适配
下载完Xcode9之后,第一件事自然是在 iPhone X(模拟器)上过把瘾,然后编译后就发现报错了
由于iPhone X的状态栏是和其他版本手机差异比较大的,因此api 变化也比较大
先后做了以下适配
适配点一:项目中使用状态栏中图标判断当前网络的具体状态
打印的 Log 报出以下错误: Trapped uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key foregroundView.'
使用 runtime 打印其所有属性,发现以下差异
// 测试代码
#import
NSMutableString *resultStr = [NSMutableString string];
//获取指定类的Ivar列表及Ivar个数
unsigned int count = 0;
Ivar *member = class_copyIvarList([[application valueForKeyPath:@"_statusBar"] class], &count);
for(int i = 0; i < count; i++){
Ivar var = member[i];
//获取Ivar的名称
const char *memberAddress = ivar_getName(var);
//获取Ivar的类型
const char *memberType = ivar_getTypeEncoding(var);
NSString *str = [NSString stringWithFormat:@"key = %s type = %s
\n",memberAddress,memberType];
[resultStr appendString:str];
}
NSLog(@"%@", resultStr);
// 其他版本的手机
key = _inProcessProvider type = @""
key = _backgroundView type = @"UIStatusBarBackgroundView"
key = _doubleHeightLabel type = @"UILabel"
key = _doubleHeightLabelContainer type = @"UIView"
key = _currentDoubleHeightText type = @"NSString"
key = _currentRawData type = {超长。。}
key = _interruptedAnimationCompositeViews type = @"NSMutableArray"
key = _newStyleBackgroundView type = @"UIStatusBarBackgroundView"
key = _newStyleForegroundView type = @"UIStatusBarForegroundView"
key = _slidingStatusBar type = @"UIStatusBar"
key = _styleAttributes type = @"UIStatusBarStyleAttributes"
key = _waitingOnCallbackAfterChangingStyleOverridesLocally type = B
key = _suppressGlow type = B
key = _translucentBackgroundAlpha type = d
key = _showOnlyCenterItems type = B
key = _foregroundViewShouldIgnoreStatusBarDataDuringAnimation type = B
key = _tintColor type = @"UIColor"
key = _lastUsedBackgroundColor type = @"UIColor"
key = _nextTintTransition type = @"UIStatusBarStyleAnimationParameters"
key = _overrideHeight type = @"NSNumber"
key = _disableRasterizationReasons type = @"NSMutableSet"
key = _timeHidden type = B
key = _statusBarWindow type = @"UIStatusBarWindow"
// iPhone X
key = _statusBar ; type = @"_UIStatusBar"
// 因此可见iPhone X的状态栏是多嵌套了一层,多取一次即可,最终适配代码为:
NSArray *children;
// 不能用 [[self deviceVersion] isEqualToString:@"iPhone X"] 来判断,因为iPhone X 的模拟器不会返回 iPhone X
if ([[application valueForKeyPath:@"_statusBar"] isKindOfClass:NSClassFromString(@"UIStatusBar_Modern")]) {
children = [[[[application valueForKeyPath:@"_statusBar"] valueForKeyPath:@"_statusBar"] valueForKeyPath:@"foregroundView"] subviews];
} else {
children = [[[application valueForKeyPath:@"_statusBar"] valueForKeyPath:@"foregroundView"] subviews];
}
3.2解决这个问题后项目跑起来发现,整个app界面上下各空出大概40pt的高度

会发现底部 UITabBar 是高出一些高度,查看层级关系后发现,同样是由于安全区的原因,UITabBar 高度由49pt变成了83pt,因此这里也要对iPhone X 及其模拟器进行适配
3.3:iPhone X 只有 faceID,没有touchID,如果in的应用有使用到 touchID 解锁的地方,这里要根据机型进行相应的适配
3.4:之前有偷懒的直接使用20替代状态栏高度,这些坑都要通过重新获取状态栏高度
CGRectGetHeight([UIApplication sharedApplication].statusBarFrame)
3.5:然而iPhone X更大的坑是屏幕的适配
首先看下屏幕尺寸

这张图反映出不少信息:
iPhone X的宽度虽然和7是一样的,但是高度多出145pt
使用三倍图是重点,而且一般认为肉眼所能所能识别的最高的屏幕密度是300ppi,iPhone X已达到458ppi(查证发现三星galaxy系列的屏幕密度是522ppi)
在设计方面,苹果官方文档有明确要求,下面结合图例进行说明:

上面这张图内含信息略多
头部导航栏不予许进行用户交互的,意味着下面这两种情况 Apple 官方是不允许的


底部虚拟区是替代了传统home键,高度为34pt,通过上滑可呼起多任务管理,考虑到手势冲突,这部分也是不允许有任何可交互的控件,但是设计的背景图要覆盖到非安全区域
状态栏在非安全区域,文档中也提到,除非可以通过隐藏状态栏给用户带来额外的价值,否则最好把状态栏还给用户
重复使用现有图片时,注意长宽比差异。iPhone X 与常规 iPhone 的屏幕长宽比不同,因此,全屏的 4.7 寸屏图像在 iPhone X 上会出现裁切或适配宽度显示。所以,这部分的视图需要根据设备做出适配。
3.6:设备信息
if ([deviceString isEqualToString:@"iPhone10,1"]) return @"iPhone 8";
if ([deviceString isEqualToString:@"iPhone10,4"]) return @"iPhone 8";
if ([deviceString isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";
if ([deviceString isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";
if ([deviceString isEqualToString:@"iPhone10,3"]) return @"iPhone X";
if ([deviceString isEqualToString:@"iPhone10,6"]) return @"iPhone X";
详细见参考链接吧, 其他不多说了.
适配iOS11&iPhoneX的一些坑
http://www.cocoachina.com/ios/20170921/20623.html
http://www.jianshu.com/p/26fc39135c34
http://www.jianshu.com/p/efbc8619d56b
http://www.jianshu.com/p/efbc8619d56b
http://www.jianshu.com/p/efbc8619d56b
http://blog.csdn.net/keep_moving31038/article/details/77685591
http://blog.csdn.net/u013263917/article/details/72895728
https://mp.weixin.qq.com/s/mpjMa-ZfftuG5rR6OApC5A
http://www.jianshu.com/p/a6e5cc20a008
https://github.com/XuYang8026/UniversalProject
http://www.jianshu.com/p/e97581110a59
https://www.cnblogs.com/Hakim/p/7566922.html
https://useyourloaf.com/blog/supporting-iphone-x/
适配 iOS 11 & iPhone X 大全的更多相关文章
- iOS 11 & iPhone X 适配资料集
本文主要简单谈谈并收集一些关于 iOS 11 & iPhone X 的适配及设计指南. iPhone X 众所周知,iPhone X 屏幕与其他的 iPhone 设备均不同,苹果称 iPhon ...
- iPhone X 适配 ( iOS 11适配 )
总结: 1.状态栏高度发生变化,解决方案:布局的时候这个高度不要写死,通过方法获取高度. 2.导航栏的视图层级结构发生变化而导致 UI(titleView.UIBarButtonItem) 问题. 3 ...
- 你可能需要为你的 APP 适配 iOS 11
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/AZFrqL9dnlgA6Vt2sVhxIw 作者:s ...
- iOS - 适配iOS 11
http://www.10tiao.com/html/330/201707/2653579210/1.html 存档 导语:iOS 11 为整个生态系统的 UI 元素带来了一种更加大胆.动态的新风格. ...
- IOS学习——iphone X的适配
说实话,对于一个刚入门iOS两个月的新手而言,在拿到这个任务的时候整个人都是懵逼的,怎么做适配?哪些地方需要适配?该怎么做?一个个问题搞得头都大了. 首先,啥都不管,先在iPhone X上运行起来看看 ...
- iOS 11适配
1.http://www.cocoachina.com/ios/20170915/20580.html 简书App适配iOS 11 2.http://www.jianshu.com/p/efb ...
- iOS 11和xcode9
最近发现了比较奇怪的问题,就是 ios10.几以前的版本,用xcode9 编写的程序 如果程序写的table是 plain的 ,那么 在 ios10.几及以下版本都会显示成group样式, ...
- 从iOS 11 UI Kit中谈谈iOS 11的新变化
北京时间9月20日凌晨1点,iOS 11终于迎来了正式版的推送,相信各位小伙伴已经在第一时间进行了升级.iOS 11毫无疑问是一次大规模的系统更新,UI.系统内核.锁屏等多方面都进行了不同程度的改进. ...
- iOS 11更新后以及iPhone X推出后工程中遇到的问题及适配
1.UITableView滑动时右侧的滑动条忽长忽短的乱跳以及MJRefresh上拉刷新死循环 这是因为tableView在iOS11默认使用Self-Sizing,tableView的estimat ...
随机推荐
- C语言程序,找出一个二维数组的鞍点。
什么是鞍点????? 鞍点就是在一个二维数组中,某一个数在该行中最大,然而其在该列中又是最小的数,这样的数称为鞍点. 昨天突然在书上看到这样的一道题,就自己尝试着写了一个找出一个二维数组中的鞍点. 好 ...
- QQ绝招
1.让QQ头像永远在前 打开"个人设定"窗口,然后在自己的昵称前点一下鼠标,再按空格键插入一两个空格(不能太多了,要不然昵称就不能完整显示了),然后点击"修改" ...
- yii2 HTML组手
1.样式和脚本 1.1 Yii 提供两个方法用于生成包含内联样式和脚本代码的标签. <?= Html::style('.danger { color: #f00; }') ?> Gives ...
- HDU 1087 Super Jumping! Jumping! Jumping! (DP+LIS)
题意:给定一个长度为n的序列,让你求一个和最大递增序列. 析:一看,是不是很像LIS啊,这基本就是一样的,只不过改一下而已,d(i)表示前i个数中,最大的和并且是递增的, 如果 d(j) + a[i] ...
- 如何使用 Visual C# 2005 或 Visual C# .NET 向 Excel 工作簿传输数据
本文分步介绍了多种从 Microsoft Visual C# 2005 或 Microsoft Visual C# .NET 程序向 Microsoft Excel 2002 传输数据的方法.本文还提 ...
- 【图论】信手拈来的Prim,Kruskal和Dijkstra
关于三个简单的图论算法 prim,dijkstra和kruskal三个图论的算法,初学者容易将他们搞混,所以放在一起了. prim和kruskal是最小生成树(MST)的算法,dijkstra是单源最 ...
- JAVA实现WC.exe功能
项目要求 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功能,并能够快速地处理多个文件. 具体功能要求: 程序处理用户需求的模式为: wc.exe [paramet ...
- Java中对比两个对象中属性值[反射、注解]
在Java中通常要比较两个对象在修改前与修改后的值是否相同,一般我们采用的是反射技术获取对象的get方法[或其他的方法]获取值并做比较.如果系统将修改的属性名称也显示出来,这样就能更直观的显示类中的哪 ...
- .NET 4中的多线程编程之一:使用Task(转载)
原文地址:http://www.cnblogs.com/yinzixin/archive/2011/11/04/2235233.html .NET 4为了简化多线程编程,提供了System.Threa ...
- Linq to Object 的简单使用示例
语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,可为 C# 和 Visual Basic 语言语法提供强大的查询功能. LINQ 引入了标准易学的数据查询和更新 ...