iOS11及xcode9的适配问题

简单写一些、还在摸索中...


1.升级iOS11后造成的变化

 1. 1升级后,发现某个拥有tableView的界面错乱,组间距和contentInset错乱,因为iOS11中UIViewControllerautomaticallyAdjustsScrollViewInsets属性被废弃了,因此当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 导航栏的新特性

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

右边为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.

@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.'

// 测试代码

#import

NSMutableString *resultStr = [NSMutableString string];

//获取指定类的Ivar列表及Ivar个数

unsignedintcount = 0;

Ivar *member = class_copyIvarList([[application valueForKeyPath:@"_statusBar"]class], &count);

for(inti = 0; i < count; i++){

Ivar var = member[i];

//获取Ivar的名称

constchar*memberAddress = ivar_getName(var);

//获取Ivar的类型

constchar*memberType = ivar_getTypeEncoding(var);

NSString *str = [NSString stringWithFormat:@"key = %s       type = %s \n",memberAddress,memberType];

[resultStr appendString:str];

}

NSLog(@"%@", resultStr);

iPhone X


其他手机

使用 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";

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容