全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

详解iOS11、iPhone X、Xcode9 适配指南

更新iOS11后,发现有些地方需要做适配,整理后按照优先级分为以下三类:

  • 单纯升级iOS11后造成的变化;
  • Xcode9 打包后造成的变化;
  • iPhoneX的适配

一、单纯升级iOS11后造成的变化

升级后,发现某个拥有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的代理方法
- (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;

四、使用Xcode9 编译后发现的问题

1. 发现“fastSocket”第三方报错,具体原因是缺少C99的头文件,引入“#include <sys/time.h>”即可


2. 导航栏的新特性

原生的搜索栏样式发生改变


右边为iOS11样式,搜索区域高度变大,字体变大

查看 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.

另外,UINavigationBar 新增属性 BOOL值 prefersLargeTitles 来实现下面的效果,并可以通过 largeTitleTextAttributes 来设置大标题的文本样式

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


iOS10及以下版本导航栏按钮层级关系图


iOS11导航栏按钮层级关系图

三、iPhone X的适配

下载完Xcode9之后,第一件事自然是在 iPhone X(模拟器)上过把瘾,然后编译后就发现报错了

由于iPhone X的状态栏是和其他版本手机差异比较大的,因此api 变化也比较大

先后做了以下适配

适配点一:项目中使用状态栏中图标判断当前网络的具体状态


出错代码

打印的 Log 报出以下错误: Trapped uncaught exception 'NSUnknownKeyException', reason: '[<UIStatusBar_Modern 0x7fcdb0805770> valueForUndefinedKey:]: this class is not key value coding-compliant for the key foregroundView.'


iPhone X


其他手机

使用 runtime 打印其所有属性,发现以下差异

// 测试代码
#import <objc/runtime.h>
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 = @"<UIStatusBarStateProvider>"
key = _showsForeground       type = B
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
  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];
  }

适配点二:解决这个问题后项目跑起来发现,整个app界面上下各空出大概40pt的高度


经常从 Github 上下载项目把玩的老司机们都知道,有些老项目在模拟器上跑起来之后也会只有 iPhone 4(320*480)的布局空间,造成这个的原因是启动图使用 Launch Images Source 设置的时候没有勾选并设置对应的图片,解决方法如下


然而iPhone X更大的坑是屏幕的适配

首先看下屏幕尺寸


这张图反映出不少信息:

  • iPhone X的宽度虽然和7是一样的,但是高度多出145pt
  • 使用三倍图是重点,而且一般认为肉眼所能所能识别的最高的屏幕密度是300ppi,iPhone X已达到458ppi(查证发现三星galaxy系列的屏幕密度是522ppi)

在设计方面,苹果官方文档human-interface-guidelines有明确要求,下面结合图例进行说明:


展示出来的设计布局要求填满整个屏幕

填满的同时要注意控件不要被大圆角和传感器部分所遮挡


安全区域以外的部分不允许有任何与用户交互的控件

上面这张图内含信息略多

头部导航栏不予许进行用户交互的,意味着下面这两种情况 Apple 官方是不允许的



  • 底部虚拟区是替代了传统home键,高度为34pt,通过上滑可呼起多任务管理,考虑到手势冲突,这部分也是不允许有任何可交互的控件
  • 状态栏在非安全区域,文档中也提到,除非可以通过隐藏状态栏给用户带来额外的价值,否则最好把状态栏还给用户

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# iOS11适配  # iPhone  # X适配  # Xcode9  # 适配  # ios xcode警告与错误的分析总结  # Xcode使用教程详细讲解(全)  # XCode编译速度慢的处理方法  # iOS10 适配-Xcode8问题总结及解决方案  # Xcode中iOS应用开发的一般项目目录结构和流程简介  # 教你如何解决XCODE升级后插件不能用问题  # iOS Xcode8更新后输出log日志关闭的方法  # xcode8 关闭控制台不打印不信息的解决方法(图文详解)  # Xcode 8打印log日志的问题小结及解决方法  # 解决Xcode8打包上传构建版本无效的办法  # 如何去掉Xcode工程中某种类型的警告  # 状态栏  # 解决方法  # 可以通过  # 所能  # 空出  # 变大  # 这张图  # 有任何  # 配点  # 文档  # 是在  # 是因为  # 也会  # 有个  # 才是  # 则是  # 更大  # 这部  # 错了  # 要注意 


相关文章: 完全自定义免费建站平台:主题模板在线生成一站式服务  h5网站制作工具有哪些,h5页面制作工具有哪些?  如何通过可视化优化提升建站效果?  如何通过虚拟主机空间快速建站?  如何在景安服务器上快速搭建个人网站?  网站制作外包价格怎么算,招聘网站上写的“外包”是什么意思?  西安专业网站制作公司有哪些,陕西省建行官方网站?  一键网站制作软件,义乌购一件代发流程?  ,如何利用word制作宣传手册?  用v-html解决Vue.js渲染中html标签不被解析的问题  如何确保FTP站点访问权限与数据传输安全?  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】  linux top下的 minerd 木马清除方法  Avalonia如何实现跨窗口通信 Avalonia窗口间数据传递  如何通过云梦建站系统实现SEO快速优化?  Dapper的Execute方法的返回值是什么意思 Dapper Execute返回值详解  个人摄影网站制作流程,摄影爱好者都去什么网站?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  定制建站哪家更专业可靠?推荐榜单揭晓  香港服务器选型指南:免备案配置与高效建站方案解析  建设网站制作价格,怎样建立自己的公司网站?  小捣蛋自助建站系统:数据分析与安全设置双核驱动网站优化  名字制作网站免费,所有小说网站的名字?  免费视频制作网站,更新又快又好的免费电影网站?  制作证书网站有哪些,全国城建培训中心证书查询官网?  制作网页的网站有哪些,电脑上怎么做网页?  定制建站流程步骤详解:一站式方案设计与开发指南  网站制作大概多少钱一个,做一个平台网站大概多少钱?  如何通过商城自助建站源码实现零基础高效建站?  MySQL查询结果复制到新表的方法(更新、插入)  高性价比服务器租赁——企业级配置与24小时运维服务  如何高效配置IIS服务器搭建网站?  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  如何在企业微信快速生成手机电脑官网?  建站VPS推荐:2025年高性能服务器配置指南  学校免费自助建站系统:智能生成+拖拽设计+多端适配  企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?  深入理解Android中的xmlns:tools属性  活动邀请函制作网站有哪些,活动邀请函文案?  Swift开发中switch语句值绑定模式  如何快速搭建个人网站并优化SEO?  成都网站制作公司哪家好,四川省职工服务网是做什么用?  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  建站VPS选购需注意哪些关键参数?  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  如何制作网站标识牌,动态网站如何制作(教程)?  如何在七牛云存储上搭建网站并设置自定义域名?  道歉网站制作流程,世纪佳缘致歉小吴事件,相亲网站身份信息伪造该如何稽查?  如何在建站主机中优化服务器配置? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。