紧凑型环境中未要求iOS 13的presentationControllerDidDismiss()弹出菜单

时间:2019-12-03 01:51:52

标签: ios swift uiviewcontroller uikit ios13

我正在为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 弹出框在表示的视图控制器中起作用,所以当在其中显示弹出框时,可能会存在生命周期问题方式吗?

关于我可能做错了什么的任何想法?

4 个答案:

答案 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();
}