关于iOS 11的一些新特性适配实践总结

前言

iOS 11 已经发布了一段时间了,随手记团队也早早的完成了适配。在这里,我们做了点总结,与大家一起分享一下关于 iOS 11 一些新特性的适配。

UIView & UIViewController

Layout Margins

iOS 11 中,官方提供了一种新的布局方法——通过 layout margins 进行布局。官方文档 Positioning Content Within Layout Margins 称,使用这种布局可以保证各个 content 之间不会相互覆盖。

总的来说,layout margins 可以视作视图的内容和内容之间的空隙。它由每个边的 insetValues 组成,分别是 top, bottom, leading and trailing. 对应的是上、下、左、右。

Auto Layout with Layout Margins

如果使用 Auto Layout 进行布局,并希望约束遵循 layout margins,那么必须要在 Xcode 中打开 Constrain to margins 选项。这样,如果父视图的 layout margins 改变,那么所有绑定于父视图 margins 的子视图都会更新布局。

注意

如果没有开启这个选项,那么所有建立的约束都会依赖于父视图的 bounds.

Manually Layout with Layout Margins

如果没有使用 Auto Layout, 而是通过设置 frame 布局的话,要遵循 layout margins 也并不困难,只需要在布局计算时使用 directionalLayoutMargins 这个属性。

var directionalLayoutMargins: NSDirectionalEdgeInsets { get set }

官方文档中阐述道,对于 view controller 的根视图,它的 directionalLayoutMargins 默认值是由 systemMinimumLayoutMargins和SafeAreaInsets 决定的。在 iPhone X 下打印根视图的这三个属性可以看到它们的关系。

override func viewDidAppear(_ animated: Bool) {
 super.viewDidAppear(animated)
 print("SafeAreaInsets :" + "\(self.view.safeAreaInsets)")
 print("systemMinimumLayoutMargins :" + "\(self.systemMinimumLayoutMargins)")
 print("directionalLayoutMargins: " + "\(self.view.directionalLayoutMargins)")

 // SafeAreaInsets :UIEdgeInsets(top: 88.0, left: 0.0, bottom: 34.0, right: 0.0)
 // systemMinimumLayoutMargins :NSDirectionalEdgeInsets(top: 0.0, leading: 16.0, bottom: 0.0, trailing: 16.0)
 // directionalLayoutMargins: NSDirectionalEdgeInsets(top: 88.0, leading: 16.0, bottom: 34.0, trailing: 16.0)
}

结果显而易见,directionalLayoutMargins 的默认值由 systemMinimumLayoutMargins 和 safeAreaInsets 组成。

注意

systemMinimumLayoutMargins 属性是否可用由 view controller 的布尔值属性viewRespectsSystemMinimumLayoutMargins决定,默认为true.

如果手动对 directionalLayoutMargins 赋值,那么在 viewRespectsSystemMinimumLayoutMargins 开启的情况下,系统会比较赋值后的 directionalLayoutMargins 和 systemMinimumLayoutMargins ,并取其较大值作为最终的 margins。

print("systemMinimumLayoutMargins :" + "\(self.systemMinimumLayoutMargins)")
print("origin directionalLayoutMargins: " + "\(self.view.directionalLayoutMargins)")

// 这里把 leading 和 trailing 分别赋值为相对于 systemMinimumLayoutMargins 的较大值20和较小值10
self.view.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 10)
print("assigned directionalLayoutMargins: " + "\(self.view.directionalLayoutMargins)")

// 打印日志可见只有 leading 的值改变为手动赋的值,trailing 依然遵循于 systemMinimumLayoutMargins
systemMinimumLayoutMargins :NSDirectionalEdgeInsets(top: 0.0, leading: 16.0, bottom: 0.0, trailing: 16.0)
origin directionalLayoutMargins: NSDirectionalEdgeInsets(top: 88.0, leading: 16.0, bottom: 34.0, trailing: 16.0)
assigned directionalLayoutMargins: NSDirectionalEdgeInsets(top: 88.0, leading: 20.0, bottom: 34.0, trailing: 16.0)

注意

如果不希望受到systemMinimumLayoutMargins的影响,那么把 view controller 的viewRespectsSystemMinimumLayoutMargins设为false即可.

Navigation bar

进入了 iOS 11,苹果为提供了更为漂亮和醒目的大标题的样式,如果想开启这样的功能,其实很简单。
只需要将 navigation bar 中的 prefersLargeTitles 置为 true 即可,这样便自动有了来自 iOS 11 中的大标题的样式。

self.navigationController.navigationBar.prefersLargeTitles = true

这里可以注意到,prefersLargeTitles 是配置在的 navigation controller 中的 navigation bar 中的。也就是说该 navigation controller 容器中的所有的 view controller 在此配置之后,都会受到影响。所以如果你要在当前的 navigation controller 中推入一个新的 view controller 的话,那么该 view controller 也会是大标题。因此为了避免这个问题,UIKit 为 UINavigationItem 提供了 largeTitleDisplayMode 属性。

该属性默认为 UINavigationItem.LargeTitleDisplayMode.automatic, 即保持与前面已经显示过的 navigation item 一致的样式。 如果想在后来的一个 view controller 避免大标题样式那么可以这么配置:

self.navigationItem.largeTitleDisplayMode = .never

除了大标题以外,在 iOS 11 中,UIKit 还为 navigation item 提供了便于管理搜索的接口。
具体参考如下:

self.navigationItem.searchController = self.searchController
self.navigationItem.hidesSearchBarWhenScrolling = true

在配置好你的 search controller 之后便可以直接提供给 navigation item 的 searchController属性上,这样的便能够在导航栏看到一个漂亮的搜索框了。

此外还可以给 navigation item 中的属性 hidesSearchBarWhenScrolling 设置为 true, 他可以使你 view controller 中管理的 scroll view 在滑动的时候自动隐藏 search bar.

Scroll view

如果使用过 view controller 管理过 scroll view 的话,想必对 automaticallyAdjustsScrollViewInsets 这个属性一定不陌生。在 iOS 11 之前,该属性可以让 view controller 自动管理 scroll view 中的 content inset. 但是,在实际在开发的过程中,这样的自动管理的方式会带来麻烦,尤其是一些在 content inset 需要动态调整的情况。

为此,在 iOS 11, UIKit 废弃了 automaticallyAdjustsScrollViewInsets 属性,并将该的职责转移到 scroll view 本身。因此,在 iOS 11 中,为了解决这个问题,有两个 scroll view 的新属性。一个是用于管理调整 content inset 行为的属性 contentInsetAdjustmentBehavior, 另一个是获取调整后的填充的属性 adjustedContentInset. 同时,UIScrollViewDelegate 也提供了新的代理方法,以方便开发者获取 inset 变化的时机:

optional func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView)

至此,对于这个「自动为开发者设置 inset」 的特性,苹果算是提供了相当完备的接口了。

不过作为开发者的我们要注意的是,如果对原本自动设置 contentInset 属性的行为有依赖,在新的 iOS 11 的适配中,可能得做出调整。

此外,为了便于开发者在 scroll view 中使用 Auto Layout. UIKit 还提供了两个新的属性。一个是 contentLayoutGuide, 它用来获取当前在 scroll view 内的内容的 layout guides. 而另一个是 frameLayoutGuide, 他用来获取实际内容的 layout guides. 这样说有点繁琐,还是看 WWDC 的原图吧:

Table view

实际上对于 table view 而言,其最大的更新就在于新的特性 Drag and Drop 了吧。但是这个特性在适配中暂时不需要考虑,本文就不介绍了,让我们一起来看看其他有意思的变化。

首先是在 iOS 11 中,table view 默认开启了 self-sizing, 可以注意到 estimatedRowHeight, estimatedSectionHeaderHeight 以及 estimatedSectionFooterHeight 都被默认设置为 UITableViewAutomaticDimension. 但是我们知道,如果原本已经实现 tableView:heightForRowAtIndexPath: 之类的方法并返回了高度,那么在布局方面是不会有影响的,这对 iOS 11 适配而言是个好消息。

在 iOS 11 中,有了新的 layout margins 的概念,因此 UIKit 也为 separator inset 做了额外的补充。现在 separator inset 可以有两个来源,一个是从 cell 的边缘开始 (UITableViewSeparatorInsetReference.fromCellEdges) ,另一个是从 table view 默认的填充开始 (UITableViewSeparatorInsetReference.fromAutomaticInsets)。其中,默认的填充由 table view 的 layout margins 进行控制。

此外,iOS 11 还为 table view 添加了更多的滑动操作的控制能力。分别可以通过以下两个 UITableViewDelegate 的方法

实现:

func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

我们可以注意到两个方法均要求返回一个 UISwipeActionsConfiguration 实例。为构造这个实例,我们还需要构造一个由 UIContextualAction 实例组成的数组。UIContextualAction 与原本的 UITableViewRowAction 大致类似,但是要注意在 contextual action 的参数 handler 中,我们需要调用 handler 参数中的 completionHandler 才能完成操作。从这一点我们可以看到,似乎在新的 action 中,我们可以做一些异步操作相关的事情。

下面是一个删除操作的示例:

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
 let contextualAction = UIContextualAction.init(style: .destructive, title: "Delete") { (style, title, completionHandler) in
  // 删除指定的数据
  completionHandler(true)
 }

 let actionsConfiguration = UISwipeActionsConfiguration.init(actions: [contextualAction])
 return actionsConfiguration
}

在 swipe actions configuration 中,我们还需要注意一点,那就是新的 performsFirstActionWithFullSwipe 属性。通过开启这个属性的配置(默认开启),我们可以为第一个动作提供 full swipe 操作 (一种通过过度滑动从而触发动作的交互) 。

如果仅仅实现了以往的编辑的代理方法,在 iOS 11 中,对于第一个动作将会默认支持 full swipe, 且不能关闭。

Face ID

如果已经做过了 Touch ID 那么实际上适配 Face ID 便并不难了。即便是不做任何的改动,估计 Face ID 也是可以直接使用的(写作时, iPhone X 还未上市),当然相关的体验肯定会打点折扣,毕竟文案以及相关的提示操作还是在仅有 Touch ID 的前提下实现的。

与以往一样,可以通过 LAContext 类实现生物识别认证。不过需要注意的是,因为支持了新的 Face ID 认证,苹果便为 LAContext 类添加了新的接口 biometryType 用于区分 Touch ID 以及 Face ID。同时,以往仅涵盖 Touch ID 的错误类型,也在 iOS 11 中废弃了,相应的,苹果提供了新的更通用的错误类型予以替代。

IOS 11 下适配UITableView

UIScrollView及其子类在IOS 11之前的版本UI显示完全正常,但是在IOS 11上面会显示奇葩的界面。

 (1)先看一下UITablevIew。

原本在VC里面的automaticallyAdjustsScrollViewInsets竟然过期了,在IOS 11下 APPLE推荐使用UIScrollView的contentInsetAdjustmentBehavior属性进行设置自动计算滚动视图的内容边距。

@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets

在IOS11的SDK下,UIScrollView的这个属性

@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior //这个属性是一个枚举类型的

{

UIScrollViewContentInsetAdjustmentAutomatic,//scrollView会自动计算和适应顶部和底部的内边距并且在scrollView 不可滚动时,也会设置内边距.

UIScrollViewContentInsetAdjustmentScrollableAxes, //自动适应边距

UIScrollViewContentInsetAdjustmentNever, //和 automaticallyAdjustsScrollViewInsets=NO有着同样的效果,不计算内边距

UIScrollViewContentInsetAdjustmentAlways//根据safeAreaInsets (安全区域)计算内边距

 }

所以,在IOS 11 下,需要设置ScrollView:

 self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

如果需要全局设置的话,需要这么设置:

if (@available(iOS 11.0, *)) {

 [[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];

}

这样设置后使用UITableview 、UICollectionView、UIScrollview的时候就不需要再单独设置该属性了,因为UIView以及他的子类都是遵循UIAppearance协议的。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

Reference

  • Positioning Content Within Layout Margins
  • directionalLayoutMargins
  • systemMinimumLayoutMargins
  • SafeAreaInsets
(0)

相关推荐

  • 110.iOS10新特性适配教程XCode8新特性解析

    iOS10 新特性 SiriKit SiriKit的功能非常强大,支持音频.视频.消息发送接收.搜索照片.预订行程.管理锻炼等等.在用到此服务时,siri会发送Intent对象,里面包括用户的请求和各种数据,可以对这个intent处理选择适当的响应. 这个功能主要是看这两个头文件(#import Proactive Suggestions 系统预先建议 背景就是iOS9的时候系统给予的主动建议会通过:Spolight搜索,Safari搜索,Handoff,或者siri建议. 在iOS10之后新增

  • 关于适配iOS11和iPhoneX的一些事

    前言 众所周知iOS11正式版终于来了,最近也把app适配了一下,其实也不是很麻烦,来看看我做的一些操作,话不多说了,来一起看看吧. 1.UITableView.UICollectionView的变化 tableView在iOS11默认使用Self-Sizing,tableView的estimatedRowHeight.estimatedSectionHeaderHeight. estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAuto

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

    更新iOS11后,发现有些地方需要做适配,整理后按照优先级分为以下三类: 单纯升级iOS11后造成的变化: Xcode9 打包后造成的变化: iPhoneX的适配 一.单纯升级iOS11后造成的变化 升级后,发现某个拥有tableView的界面错乱,组间距和contentInset错乱,因为iOS11中 UIViewController 的 automaticallyAdjustsScrollViewInsets 属性被废弃了,因此当tableView超出安全区域时,系统自动会调整SafeAre

  • iOS 11 下适配UITableView 问题

    9月份苹果发布了IOS11和Iphone X,这一操作系统一硬件对于开发者适配上面还是造作了不少蛋疼的地方.先来看看IOS 11,这些蛋疼的需要适配的地方: 1.UIScrollView及其子类在IOS 11之前的版本UI显示完全正常,但是在IOS 11上面会显示奇葩的界面. (1)先看一下UITablevIew. 原本在VC里面的automaticallyAdjustsScrollViewInsets竟然过期了,在IOS 11下 APPLE推荐使用UIScrollView的contentIns

  • iOS 11更新后及iPhone X推出后工程中遇到的问题及适配方法

    1.UITableView滑动时右侧的滑动条忽长忽短的乱跳以及MJRefresh上拉刷新死循环 这是因为tableView在iOS11默认使用Self-Sizing,tableView的estimatedRowHeight.estimatedSectionHeaderHeight.estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,MJRefresh的KVO会监听错误的contentoffset,造成

  • iOS11和iPhoneX适配的一些坑

    本文转载于:http://www.cocoachina.com/ios/20170921/20623.html 导航栏 导航栏高度的变化 iOS11之前导航栏默认高度为64pt(这里高度指statusBar + NavigationBar),iOS11之后如果设置了prefersLargeTitles = YES则为96pt,默认情况下还是64pt,但在iPhoneX上由于刘海的出现statusBar由以前的20pt变成了44pt,所以iPhoneX上高度变为88pt,如果项目里隐藏了导航栏加了

  • 浅谈Xcode9 和iOS11适配和特性

    今天升级了Xcode9 刚才写了一篇 爱劈叉的齐刘海 现在说说新的东西把,有些简直不能再恶心了但有些简直不能再贴心 首先是跳转, 之前按住Command + 左键 就可以跳转了;然而今天我发现 除了这个: Jump to Definition(^⌘):跳转类头文件或定义 Show Quick Help(⌥):显示帮助文档 Edit All in Scope:编辑文档内所有匹配内容 在这里我要说,对于懒得不行的我,简直要吐,多了一步操作 效率降低很多的好吗? 那么好,你试试 Command + 右

  • iOS11&iPhoneX适配&Xcode9打包注意事项

    1,适配UITableView if#available(iOS11.0, *) { self.contentInsetAdjustmentBehavior= .never self.estimatedRowHeight=0 self.estimatedSectionHeaderHeight=0 self.estimatedSectionFooterHeight=0 }else{ } 2,适配UIScrollView if#available(iOS11.0, *) { scrollView?.

  • iOS11适配工作及导航栏影藏返回文字的解决方法

    前言 本文主要介绍了关于iOS11适配及导航栏影藏返回文字的解决方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.iOS11适配工作 这是一篇 WWDC Session 204 "Updating Your App for iOS 11" 的总结,里面的内容涉及到了产品.设计以及开发需要了解的内容. 在 "iPad" 以及 "iPhone 的 Landscape" 下, UITabBarItem 图片和文字并排排列了,并

  • 关于iOS 11的一些新特性适配实践总结

    前言 iOS 11 已经发布了一段时间了,随手记团队也早早的完成了适配.在这里,我们做了点总结,与大家一起分享一下关于 iOS 11 一些新特性的适配. UIView & UIViewController Layout Margins iOS 11 中,官方提供了一种新的布局方法--通过 layout margins 进行布局.官方文档 Positioning Content Within Layout Margins 称,使用这种布局可以保证各个 content 之间不会相互覆盖. 总的来说,

  • C++11/14的新特性(更简洁)

    新的字符串表示方式--原生字符串(Raw String Literals) C/C++中提供了字符串,字符串的转义序列,给输出带来了很多不变,如果需要原生义的时候,需要反转义,比较麻烦. C++提供了,原生字符串,即字符串中无转义,亦无需再反义.详细规则见带码: #include <iostream> using namespace std; string path = "C:\Program Files (x86)\alipay\aliedit\5.1.0.3754";

  • IOS11新特性与兼容适配

    IOS11发布以来,很多新的特性为开发工作提供了方便,小编在此给大家介绍一下IOS11的新特性以及在兼容适配等做的工作. 1. UIView变化 1.1. 更加方便的RTL边距设置 在之前的系统中我们会使用layoutMargins来获取和设置控件显示内容部分的边缘与控件边缘的距离.在iOS 11中,新增directionalLayoutMargins属性来指定边距.这两个属性的结构定义如下: typedef struct UIEdgeInsets { CGFloat top, left, bo

  • iOS 11 safeArea详解及iphoneX 适配

    最近看了许多iPhone X适配的文章,发现很少有介绍safeArea的,就来随便写写 现在对于iPhone X的适配,有一种常见的做法是给导航栏或tabbar增加一个固定的距离,比如顶部增加44pt,底部增加34pt.这种写死距离的做法乍看上去挺简单,其实并不好,理由如下 不适合多机型的适配,如果以后出了一种带刘海的iPad,需要预留出来的距离就未必是现在写死的距离 不适合需要支持横竖屏的app,横屏顶部不需要增加距离,反而是左右各有44pt,底部的距离也和竖屏不同 不够动态.还是举个例子,假

  • iOS开发之路--微博新特性页面

    BeyondAppDelegate.m // // BeyondAppDelegate.m // 20_帅哥no微博 // // Created by beyond on 14-8-3. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import "BeyondAppDelegate.h" #import "BeyondViewController.h" #import "NewFe

  • C++11的新特性简单汇总介绍 (一)

    什么是C++11 C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report 1(TR1)程序库(数学的特殊函数除外). C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decltype,和模板的大量改进. 1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己

  • C++11新特性中auto 和 decltype 区别和联系

    C++11新特性中auto 和 decltype 区别和联系 一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型.然而做到这一点并非那么容易(特别是模板中),有时候根本做不到.为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型.和原来那些只对应某种特定的类型说明符(例如 int)不同.auto 让编译器通过初始值来进行类型推演.从而获得定义变量的类型,所以说 auto 定义的变量必须有初始

随机推荐