在 WWDC19 上,苹果推出了一种新的 present 视图控制器的方式,如下图所示,苹果将它称为 sheet。
以 sheet 方式 present 出来的视图控制器,在视觉上,能够让用户更加清晰认识到正在进行的操作的上下文,并且也自带了非常舒适的拖拽关闭的交互手势。因此从 iOS13 起,苹果将视图控制器的 modalPresentationStyle
的默认值从 UIModalPresentationFullScreen
修改为 UIModalPresentationAutomatic
,对于自定义的视图控制器,系统会自动裁决为 UIModalPresentationPageSheet
,即图中这种形式。在 WWDC21 上,苹果继续对 sheet 进行了一些基础性的功能优化,提供了自定义 sheet 高度、可选拖拽指示器、水平方向可变宽度等等新的能力,使得开发者可以创造出更加灵活、美观、方便的应用界面和交互方式。
本文基于 WWDC Session 10063[1] 梳理而来。
在介绍 WWDC21 上提供的这些新特性之前,让我们先简要回顾下 WWDC19 上 sheet 的特性。
假设有一段代码:
let myVC = MyViewController()
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
myVC.present(imagePicker, animated: true)
在执行后,myVC 就成为 presentingViewController
,而 imagePicker 就成为 presentedViewController
。在 present 时,由于 imagePicker 的 modalPresentationStyle
没有被显式设置,因此就是默认值 UIModalPresentationAutomatic
,也即 UIModalPresentationPageSheet
。而在 iOS13 之前,这个默认值是 UIModalPresentationFullScreen
。因此当这段程序运行在 iOS13 之前及 iOS13 上时,presentingViewController
和 presentedViewController
的生命周期调用会有一些变化。
如下是 modalPresentationStyle
为 UIModalPresentationFullScreen
时两者的生命周期方法的调用情况。
如下是 modalPresentationStyle
为 UIModalPresentationPageSheet
或UIModalPresentationFormSheet
时,两者的生命周期方法的调用情况。
比较两者可以发现,sheet 这种方式在 present 的时候,presentingViewController
的几个重要的生命周期方法都不会执行。这是由于,viewDidDisappear/viewWillAppear
这些生命周期方法,是在视图控制器从视图层级上移除或者添加时调用的,而在 sheet 中,presentingViewController
是一直存在于视图层级中的,因此这些生命周期方法就不会调用了。
因此,一些依赖于生命周期方法的埋点和展现统计逻辑,在 iOS13 可能会有不符合预期的表现,需要格外关注。
对于其他一些 presentationStyle 的生命周期调用顺序,笔者制作了一个简单的 Demo[2],这里直接给出测试结论,感兴趣的同学可以自行 clone Demo 来验证。
presentation_lifecycle
以 sheet 方式 present 出来的视图控制器,系统会为它添加一个拖拽关闭的手势。但如果用户在 present 出来的视图控制器上进行了一些编辑改动,而一个不小心的拖拽导致这个视图控制器被直接 dismiss,进而丢失了刚刚的改动,那么用户可能会不太高兴。在这种情况下,你可以通过设置视图控制器的 modalInPresentation
属性为 YES 来避免视图控制器被直接 dismiss。
如果需要在拖拽视图控制器时,提醒用户是否需要保存已经编辑的内容,则可以实现 UIAdaptivePresentationControllerDelegate
,这个协议有以下几个方法:
optional func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool
optional func presentationControllerWillDismiss(_ presentationController: UIPresentationController)
optional func presentationControllerDidDismiss(_ presentationController: UIPresentationController)
optional func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController)
我们用一张图来说明这些方法在什么情况下会被调用:
presentedViewController
的 isModalInPresentation
为 YES,当拖拽时,会调用 presentationControllerDidAttemptToDismiss:
,可以在这个方法中询问用户是否需要保存编辑的内容presentedViewController
的 isModalInPresentation
为 NO,当拖拽时,会先调用 presentationControllerShouldDismiss:
,如果这个方法返回 NO,也会调用 presentationControllerDidAttemptToDismiss:
presentationControllerShouldDismiss
: 方法返回 YES,则会依次调用 presentationControllerWillDismiss:
和 presentationControllerDidDismiss:
两个方法。苹果也贴心地给出了一个Demo:Disabling the Pull-Down Gesture for a Sheet,来演示这个场景。
在 iOS15 上,UIViewController 新添加了一个属性 sheetPresentationController
,它的类型是 UISheetPresentationController
,是 UIPresentationController
的子类。如果一个视图控制器的 modalPresentationStyle
为 .formSheet 或 .pageSheet,那么这个视图控制器的 sheetPresentationController
就不为空。iOS15 上引入的若干个 sheet 的新特性,都是通过直接对视图控制器的 sheetPresentationController
的属性进行配置而得到的。
在 iOS15 前,开发者无法控制 sheet present 出来后的尺寸,sheet 在竖屏弹出时,高度是固定的,宽度和屏幕等宽;在横屏弹出时,sheet 则会占据全屏。
sheet_horizontal
而在 iOS15 之后,开发者能够自定义 sheet 的大小了。
首先,在竖屏方向上弹出时,可以通过设置 detents 来指定 sheet 的高度。detents 是一个数组,表示 sheet 能够展示的高度的种类。系统预置了 medium 和 large 两种高度类型。medium 表示 sheet 的高度占据大约一半的屏幕高度,而 large 的高度则和之前 sheet 的默认高度相同。如果 detents 数组只有一个元素,则 sheet 的高度是固定的,如果有两个元素,则用户可以通过拖拽将 sheet 的高度在 medium 和 large 间进行调节。
resize
其次,在水平方向上弹出时,可以将 prefersEdgeAttachedInCompactHeight
设置为 true,这个属性表示水平方向上 sheet 的宽度将和安全区域的宽度一致。如果再将 widthFollowsPreferredContentSizeWhenEdgeAttached
设置为 true,那么 sheet 的宽度就将等于 preferredContentSize
所指定的宽度。
一些用户可能没有意识到能够通过拖拽改变 sheet 的高度,所以为了给用户更加直接明了的提示:“嘿,我这个视图可是能拖拽的哦”,可以设置 prefersGrabberVisible
为 true。设置之后,在 sheet 上就会出现一个拖拽指示器:
grabber
另外,当 sheet 处于 medium 状态时,如果 sheet 里面有个可滚动的 scrollView,那么在比较靠近 sheet 头部边缘的位置滚动 scrollView 时,很有可能会导致 sheet 的高度也被意外地调整,此时可以设置 prefersScrollingExpandsWhenScrolledToEdge
为 false,就可以阻止这个行为。
如果给 detents 传入了多个元素,那么除了让用户来拖拽改变 sheet 的高度外,还可以使用 selectedDetentIdentifier
来在代码中指定某些状态下 sheet 的高度,例如 Keynote 中图片选择器的 Demo 里,当用户从处于 large 模式的图片选择器中选中一张图片后,可以在回调中设置 selectedDetentIdentifier
为 medium 来将图片选择器调整到半屏高度。这个设置被包裹在 animateChanges
中的话,高度的变化还会自动拥有漂亮的动画过渡效果。
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
if let sheet = picker.popoverPresentationController?.adaptiveSheetPresentationController {
sheet.animateChanges {
sheet.selectedDetentIdentifier = .medium
}
}
}
detent_select
这个特性也许是本次 sheet 的改变中最为重要的一个特性:可以和 sheet 背后的视图控制器进行交互了。在之前,sheet 在 present 后,系统会在 presentingViewController
和 sheet 之间加上一个暗色的遮盖视图,这个遮盖视图的存在会阻止用户和 presentingViewController
之间进行交互。现在则可以通过设置 sheet 的 largestUndimmedDetentIdentifier
来指定一个最小高度,当 sheet 处于这个最小高度时,系统不会添加遮盖视图,当 sheet 的高度大于这个值时,会被加上一个暗色遮盖视图。
在
Xcode 13
实际装载的iOS 15 SDK
中,smallestUndimmedDetentIdentifier
被修改为largestUndimmedDetentIdentifier
,但其行为仍然和上述表述保持一致。
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
sheet. largestUndimmedDetentIdentifier = .medium
}
present(picker, animated: true)
}
在 iPad 上,popover 相较于 present,是更加自然的交互。但是由于 iPad 支持分屏并调整分屏宽度,因此应用的实际宽度也是变化的。因此我们希望在应用实际宽度较宽的时候,让视图控制器以 popover 的方式显示; 而在应用实际宽度较窄时,以 sheet 的方式进行显示。
popover
为了达到此目的,我们只需要对之前的代码进行很少的修改: 可见,为了适配 iPad,我们需要:
modalPresentationStyle
显式指定为 .popoverpopoverPresentationController
popoverPresentationController
上获取 adaptiveSheetPresentationController
,之后的配置等同于 sheetPresentationController
在 WWDC21 中,苹果对 sheet 进行了一次篇幅不小的更新,加上了很多实用的新特性。有了这些新特性的加持,我们能够为用户提供更加精美舒适的应用界面和交互体验。快点尝试这些新特性,让你的用户耳目一新吧~
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/AR3SH9ddgKAiBDOVuPPUug
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。