我正在为iOS 13的新“卡片式”模式视图更新我的应用程序。使用UIAdaptivePresentationControllerDelegate
的{{1}}和presentationControllerDidAttemptToDismiss()
函数,一切运行良好。但是,对于将presentationControllerDidDismiss()
设置为.modalPresentationStyle
的视图,在紧凑环境(例如拆分或滑盖的电话或iPad)中显示时,不会调用.popover
。在常规尺寸的课堂环境(例如iPad全屏)中显示时,可以正确调用它。
我的代码设置起来非常简单:
显示弹出窗口的代码:
presentationControllerDidDismiss()
然后,显示的控制器符合func showChooser() {
// other setup code...
navController.modalPresentationStyle = .popover
navController.popoverPresentationController?.barButtonItem = self.viewController?.navigationItem.leftBarButtonItem
self.present(navController, animated: true)
}
并进行设置:
UIAdaptivePresentationControllerDelegate
当视图在常规尺寸级别的环境中显示时,它会正确显示为弹出框。当用户在弹出窗口外点击时,将调用// This is in the presented view controller (i.e. the popover)
override func viewDidLoad() {
// other setup removed for brevity…
self.navigationController?.presentationController?.delegate = self
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("did dismiss")
self.cancel?()
}
。但是,在紧凑的环境中显示相同的代码时,可以正确显示(作为卡片样式),但是当用户向下拖动视图时,不会调用presentationControllerDidDismiss()
。
如果我将presentationControllerDidDismiss()
更改为.modalPresentationStyle
或.pageSheet
之类的东西,那么无论是紧凑演示还是常规演示,都可以正常工作。
在紧凑的环境中,我尝试使用委托人的.formSheet
将样式更改为adaptivePresentationStyle()
,但是.formSheet
仍未正确调用。
更新:
我应该提到,我当前的解决方法是检查尺寸等级并根据需要更改presentationControllerDidDismiss()
:
.modalPresentationStyle
这可行,但是似乎仅使用if self.traitCollection.horizontalSizeClass == .compact {
navController.modalPresentationStyle = .automatic
} else {
navController.modalPresentationStyle = .popover
navController.popoverPresentationController?.barButtonItem = self.viewController?.navigationItem.leftBarButtonItem
}
样式就可以适当地适应并调用正确的委托方法。
更新2: 我已经更新了上面的代码,以阐明 presented 视图控制器是处理委托方法的控制器。
此外,在深入研究之后,我注意到,如果 presenting 视图控制器是委托并处理委托方法,那么这一切都可以按预期进行。由于它还可以在紧凑的环境中为所有.popover
的 except 弹出框在表示的视图控制器中起作用,所以当在其中显示弹出框时,可能会存在生命周期问题方式吗?
关于我可能做错了什么的任何想法?
答案 0 :(得分:1)
在navController.presentationController?.delegate = // *
navController.viewControllers[0]
之后放置self.present(navController, animated: true)
,否则您的presentationController
可能为空
答案 1 :(得分:0)
问题仅仅是时机之一。您正在第二个视图控制器中执行此操作:
override func viewDidLoad() {
self.navigationController?.presentationController?.delegate = self
}
那太晚了。您可以在配置和执行演示的位置设置委托:
func showChooser() {
navController.modalPresentationStyle = .popover
navController.popoverPresentationController?.barButtonItem =
self.viewController?.navigationItem.leftBarButtonItem
navController.presentationController?.delegate = // *
navController.viewControllers[0]
as! UIAdaptivePresentationControllerDelegate
self.present(navController, animated: true)
}
如果您希望坚持让第二个视图控制器将自己设置为委托,请尽早进行。第一个好机会是willMove
:
override func willMove(toParent parent: UIViewController?) {
self.parent?.presentationController?.delegate = self
}
答案 2 :(得分:0)
感谢该示例的堆积-只是为了扩展Matt的细节,并为那些寻求通用示例(通过创建独立的viewController)的人们带来好处,我相信类似以下的内容也应该起作用:>
func presentExampleViewController() {
// Any other setup code specific to the view in your app can go here...
let exampleViewController = SomeCustomViewController()
exampleViewController.presentationController?.delegate = exampleViewController
self.present(exampleViewController, animated: true)
}
答案 3 :(得分:0)
如果您的 viewController 嵌套在另一个 navigationviewController 中
/// <summary> detect changes to Address Entities and redirect them through the provider </summary>
public override int SaveChanges()
{
foreach (var entry in this.ChangeTracker.Entries())
{
if (entry.Entity is Address a)
{
switch(entry.State)
{
case EntityState.Modified:
case EntityState.Added:
{
if (AddressProvider.LoadFromService)
{
if (String.IsNullOrEmpty(a.UserId))
a.UserId = a.User.Id;
AddressProvider.SaveAddressInAPI(a);
}
if (!AddressProvider.UpdateDatabase)
entry.State = EntityState.Unchanged;
break;
}
case EntityState.Deleted:
{
// no mention of how to handle delete, so we'll add a blank one
if (AddressProvider.LoadFromService)
{
string userId = a.UserId;
if (String.IsNullOrEmpty(a.UserId))
userId = a.User.Id;
AddressProvider.SaveAddressInAPI(new Address { UserId = userId });
}
if (!AddressProvider.UpdateDatabase)
entry.State = EntityState.Unchanged;
break;
}
case EntityState.Unchanged:
default:
continue;
}
}
}
return base.SaveChanges();
}