iOS 13中的模态模态屏幕演示

大家好!


我叫Ilya,来自Tinkoff.ru。 我为您翻译了杰夫·哈克沃思(Geoff Hackworth)撰写的一篇文章,内容涉及模态表示样式在iOS 13中的变化,它如何影响以及与早期版本的iOS和Xcode的向后兼容性。


图片


引言


在撰写本文时,WWDC 2019即将结束。 像许多iOS开发人员一样,我会慢慢处理Apple提供给我们的所有新信息,并且在接下来的几周(甚至几个月!)中,我将尝试尽可能多地观看视频。
我对自己的应用程序有三个问题:


  • 我当前的应用程序可以在iOS 13上正常运行吗? 根据创建应用程序的Xcode版本,Apple具有向后兼容性的悠久历史。 历史记录表明,在Xcode 10中为iOS 13创建的应用程序的行为就像在iOS 12上运行一样。但这并非总是如此。
  • 使用Xcode 11 / iOS 13构建应用程序时,我的应用程序可以工作吗? 使用最新工具进行的构建允许应用程序以新的方式工作,从而绕过了与iOS早期版本的向后兼容性。 东西坏了吗?
  • 可以/应该进行哪些更改以使我的应用程序更好地工作,或者利用新的iOS 13功能? 这是最大的任务,将需要更多的时间来研究和实施。 本研究仅针对另一篇文章。

我尚未在真实设备上安装iOS 13,但是我可以通过在iOS 13模拟器上安装Xcode-10中创建的应用程序来测试项目1。
我仍在研究第2点,但是基于我的初步测试和阅读其他发现相似发现的开发人员的推文,使用Xcode 11构建应用程序时,我发现了许多行为上的变化。同化,但是在这篇文章中,我想重点介绍iOS 13中UIViewController呈现中的立即明显且可能具有破坏性的更改。


更改默认的模式呈现样式


默认情况下,模式演示现在是“页面”(原始页面),而不是全屏。 modalPresentationStyle的文档如下:


默认值为iOS的UIModalPresentationAutomatic(从iOS 13.0开始)和早期版本的UIModalPresentationFullScreen。
默认情况下,如果将modalPresentationStyle设置为modalPresentationStyle,则UIViewController使用UIModalPresentationPageSheet,但是系统控制器可以为UIModalPresentationAutomatic使用不同的显示样式。

此更改对iPhone和iPad的影响不同。


iPhone上的模态演示


除非使用UIAdaptivePresentationControllerDelegate方法防止进行调整,否则iPhone上的Page Sheet,Form Sheet和Popover的显示样式将调整为全屏显示。 例如,设置屏幕可以以表格形式显示,以便在iPhone上以全屏模式显示,而在iPad上以简化形式显示。 从技术上讲,外观/适应性取决于宽度。 Landscape iPhone Plus和XS Max设备上的页面表单/表单表单/弹出式演示文稿无法覆盖整个屏幕,因为它们具有通常的宽度。 iPad的外观取决于滑盖和多任务处理模式的大小。
以下屏幕快照显示了iPhone XS上三种情况下的表单演示:内置于iOS的Xcode 10,内置于iOS 13的Xcode 10,内置于iOS 13的Xcode 11。



iOS 12与iOS 13的向后兼容性(用于构建Xcode 10)会产生全屏视图。 在iOS 13中,已分组的UITableView的样式已更改,可以在没有标题的情况下在第一部分上方隐藏空间。 在iOS 13上启动时,即使Xcode 10 / iOS 12的构建也表现出不同的行为,这并不是我所期望的。
当然,iOS 13中最大的变化是卡片显示(原始的类似卡片的外观)。 UIViewController的尺寸已减小,但顶部仍在新推出的UIViewController后面略显可见。 根UIViewController后面的UIWindow也有点可见。 默认情况下,UIWindow的黑色背景看起来很棒,尤其是在带有缺口的设备上。 我的一些应用程序将UIWindow背景设置为白色(由于我不再记得的原因),而且看起来非常难看。 我很快解决了!


新的模式显示样式中的UIViewController行为


如果显示的UIViewController显示另一个UIViewController,则卡片重叠并带有漂亮的动画。 请注意,只有显示的最后一个UIViewController和前面的一个可见:



行为上另一个潜在的重要差异是显示(原始呈现)UIViewController发生了什么。 完全覆盖UIViewController的全屏演示(全屏演示)将从层次结构中删除UIViewController。 但是,对于新卡片展示,UIViewController必须保留在层次结构中,因为它仍然可见。 但是,尽管用户一次只能看到两个UIViewController,但是重复显示UIViewController并不会从层次结构中删除较低的UIViewController。


调整大小


新的卡片样式外观意味着所显示的UIViewController在iOS 13上不像在iOS 12上那么高:



我要全屏!


以全屏模式显示UIViewController的显式请求将阻止显示卡片式屏幕。 但是,这可能会破坏iPad上应用程序的行为。 请不要试图检查设备习惯用法,并为iPhone和iPad使用其他演示样式。 如果最近几年对我们有所启发,那就是我们不应基于设备类型或屏幕尺寸进行假设。 如果希望iPad显示“页面/表单”,但iPhone具有“全屏”,则可以使用UIAdaptivePresentationControllerDelegate在紧凑的宽度条件下适应全屏模式。


iPad上的模态演示


表格


表单样式中显示的屏幕在iOS 13中保持不变:



页表


如上所述,iOS 13中的默认modalPresentationStyle现在为页面表单。 在iPad上,这种样式的UIViewController的大小在纵向和横向上都发生了变化:




与iOS 12中一样,对“可读内容”(原始可读内容大小)的限制会在更改内容大小类别(原始内容大小类别)时更改其大小。 在某些内容大小类别上,iOS 12和13上的实际大小似乎有所不同。
以Page Sheet样式呈现的UIViewController本身在iOS 13上也随着内容大小类别的增加而增加。 这是“额外的超大”类别(可用的最大尺寸,不包括较大的辅助功能尺寸):




其他类型的演讲


modalPresentationStyle的文档如下:


默认情况下,UIViewController将UIModalPresentationAutomatic定义为UIModalPresentationPageSheet,但是其他系统控制器可能会不同地定义UIModalPresentationAutomatic。

我不确定100%是否适用于“其余系统控制器”的所有规则,但是我发现在不设置modalPresentationStyle情况下显示分屏式modalPresentationStyle可以显示整个卡片的视图:



滑动即可关闭


影响iPhone和iPad的另一个重要变化是,可以通过向下滑动以交互方式关闭不在全屏模式下的模态显示屏幕(弹出窗口除外)。 此时,后面的屏幕将返回全屏模式:



请注意,在此示例中,我将“关于”屏幕放置在设置屏幕的UINavigationController中。 尽管UINavigationController没有显示其根控制器,但可以进行交互式关闭。


请不要搅拌我!


如果您依靠用户单击“完成”按钮(或类似按钮)或跳回到导航控制器堆栈的顶部以关闭模态显示的UIViewController,则要关闭的新滑动行为可能会破坏您的应用程序,因为您的屏幕关闭处理程序不会将被执行。
例如,在我的Pomodoro Timer Pommie应用程序中,用户可以转到“设置”屏幕上的子屏幕,并添加或编辑计时器配置文件(特定类型任务的工作/休息时间配置):



对于Pommie,如果用户通过滑动关闭整个设置屏幕,我认为这是正常的(也是安全的)。 用户可能会希望他们可以一次性关闭屏幕,而我希望我的应用程序能够在iOS 13中正常运行。但是,我觉得在“添加/更改计时器配置文件”屏幕上,您无法让用户通过滑动来关闭屏幕,因为存在变更丢失的风险。 用户可能不完全清楚这样的关闭之后会发生什么。
解决此问题的一部分是新的UIViewController: isModalInPresentation 。 从文档中:


当您想使屏幕变为模态时,将设置modalInPresentation。 启用此选项后,演示文稿将阻止交互式关闭,并忽略UIViewController边界之外的事件,直到将此参数设置为NO。

为了在iOS 13的“设置”屏幕上获得类似于iOS 12的行为,我可以将true设置为isModalInPresentation显示的UINavigationController的isModalInPresentation属性。 如果用户尝试向下滑动以将其关闭,则屏幕将略微移动,但会阻止用户的操作并且不会关闭。
该属性可以随时更改,例如,如果用户尚未进行更改,则可以关闭该属性;如果用户未明确保存更改,则这些更改将丢失。 但是,一旦进行了更改,就可以设置isModalInPresentation来防止通过滑动关闭。 这将迫使用户单击“取消”或“保存”按钮。


接近检测


如前所述,当可修改的UIViewController使用“取消”,“完成”或“保存”按钮关闭时,某些应用程序可能需要执行一些代码(而不只是关闭它)。 例如,您可能需要重新启动游戏中的计时器或根据用户已更改的某些信息采取行动。 如果用户通过滑动关闭屏幕,则不会执行此代码。 您的按钮未被按下,因此不会调用其动作处理程序。 这可能会破坏您的应用程序的行为。
避免此问题的最简单方法是防止使用isModalInPresentation进行交互式关闭。 用户将必须按下按钮以关闭视图控制器,就像在iOS 13之前一样。但是还有另一种方法...
iOS 13添加了一些新的UIAdaptivePresentationControllerDelegate方法。 它们允许另一个对象(通常是一个将另一个屏幕显示为模式的屏幕)控制是否允许交互式关闭(使用isModalInPresentation的替代方法)并接收有关交互式关闭何时开始或结束的信息。 从WWDC 2019的第15分钟开始,在WWDC 2019 224:为iOS 13更新UI方面,这些方法已得到充分记录并得到了明确说明。 请注意,如果用户开始滑动关闭,改变主意然后再次滑动,则可以多次调用presentationControllerWillDismiss 。 在presentationControllerDidDismiss方法中,您需要执行其他代码,这些代码在按下“取消”,“完成”或“保存”按钮时被调用(当然,您无需关闭显示的屏幕)。 如果UIViewController以编程方式关闭,则不会调用这些方法。 因此,您仍然需要在按钮处理程序(或您自己的委托)中执行代码,即使在iOS 13上工作,这也会导致关闭。
让我们看一下presentationControllerDidAttemptToDismiss委托方法。 如果用户尝试滑动以将其关闭,但是isModalInPresentation导致锁定,则将调用该方法。 在带有WWDC的视频中,建议显示一个操作列表,并询问用户是否要放弃更改或保存更改。 如果显示的UIViewController具有“取消”和“保存/完成”按钮,这似乎是一个好主意:创建新注释,编辑对象的属性等。
我认为对于带有“取消”和“保存”按钮的导航堆栈中的嵌套UIViewController,这更加复杂。 执行保存的代码可能在UIViewController中,该代码在堆栈上高一级,而不在实现UIAdaptivePresentationControllerDelegate的对象中。 尝试将用户的选择重定向到可以执行保存的对象可能并不完全合适。 在我自己的应用程序中,我想我将阻止那些需要显式撤消/保存操作的屏幕关闭,如果它们不在导航堆栈的顶部。


资源资源


WWDC 2019视频将是找出iOS 13中发生了什么更改的最佳位置,您需要对应用程序进行哪些更改以使它们在Xcode 11中构建时可以正常工作,以及可以进行哪些更改以改进它们以利用新功能功能。 以下是一些入门视频:



结论


到目前为止,我还没有发现在iOS 13下的Xcode 10中创建的应用程序存在任何问题。向后兼容性在这里确实有效。 看到分组表的外观有所变化,我感到有些惊讶。
Xcode 11构建需要一些小的修复,以应对本文中讨论的模式表示形式的更改。 可能会有一些我尚未发现的变化。
彻底测试您的模态演示(尤其是使用搜索栏)! 确定是否要允许用户通过滑动关闭模式屏幕,并使用isModalInPresentation获得必要的行为,以防止由于错误的滑动​​而导致意外数据丢失。 为了获得更大的灵活性和控制力,请使用UIAdaptivePresentationControllerDelegate

Source: https://habr.com/ru/post/zh-CN467969/


All Articles