自适应弹出窗口上的关闭按钮

时间:2014-08-12 22:41:21

标签: ios objective-c uikit uistoryboard

在故事板中,我有一个带有按钮的根视图控制器,该按钮触发“弹出”按钮。 segue到包含UITableViewController的UINavigationController。我希望导航控制器出现在iPhone和iPad上。

在iPad上,这在popover中效果很好。

在iPhone上,我得到了模态演示,所以现在我需要一个额外的条形按钮项来消除模态视图。通过观看WWDC视频,我在根视图控制器中尝试了以下内容:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    UIViewController *vc = segue.destinationViewController;
    vc.popoverPresentationController.delegate = self;
}

- (void)dismissPopover {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
    UINavigationController *nvc = (UINavigationController *)controller.presentedViewController;
    UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismissPopover)];
    nvc.topViewController.navigationItem.leftBarButtonItem = bbi;
    return nvc;
}

我理解-presentationController:viewControllerForAdaptivePresentationStyle:方法只应在UI自适应时调用,即模态,但它根本不会被调用,即使在iPhone上作为模态运行也是如此。

3 个答案:

答案 0 :(得分:13)

对于那些想要快速剪切和粘贴的人来说,这是尼克斯的正确答案的Swift版本。

注意:这是在iPad上创建一个弹出框,但是在iPhone上有一个关闭按钮的模态表。

在Xcode 6.3故事板中,您连接了一个视图控制器并将segue指定为“作为弹出窗口存在”

下面的代码应该放在视图控制器中,该控制器会切换到popover,而不是popover本身:

首先设置popover委托:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "myPopoverSegueName" {
        segue.destination.popoverPresentationController?.delegate = self
        return
    }
}

然后添加委托扩展并动态创建导航控制器/关闭按钮:

extension myViewController: UIPopoverPresentationControllerDelegate {

    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        let btnDone = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.dismissPopover))
        let nav = UINavigationController(rootViewController: controller.presentedViewController)
        nav.topViewController?.navigationItem.leftBarButtonItem = btnDone
        return nav
    }

    @objc private func dismissPopover() {
        dismiss(animated: true, completion: nil)
    }

}

答案 1 :(得分:12)

好的,我已经成功实现了它。我认为我的问题是popoverPresentationController属性遍历视图控制器层次结构,直到它找到一个带有popoverPresentationController的视图控制器,即如果我在视图控制器内部的导航控制器内有一个视图控制器popoverPresentationController将转到导航控制器并使用它的属性。为此,视图控制器必须是导航控制器的子级。在我尝试使用popoverPresentationController的所有要点中,情况并非如此,例如initviewDidLoadviewWillAppear。出于某种原因,即使willMoveToParentViewController被调用,也不会调用didMove。所以我不知道如何在调用ppc委托方法之前在导航控制器中的vc中引用popoverPresentationController

但是,您可以在prepareForSegue中的呈现视图控制器中引用它,但您需要明确告诉它要使用的演示样式。这是我放置在呈现视图控制器中的代码:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    UIViewController *dest = segue.destinationViewController;
    dest.popoverPresentationController.delegate = self;
}

- (void)dismiss {
    [self dismissViewControllerAnimated:YES completion:nil];
}


- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
    return UIModalPresentationFullScreen; // required, otherwise delegate method below is never called.
}

- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
    // If you don't want a nav controller when it's a popover, don't use one in the storyboard and instead return a nav controller here
    UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismiss)];
    UINavigationController *nc = (UINavigationController *)controller.presentedViewController;
    nc.topViewController.navigationItem.leftBarButtonItem = bbi;
    return controller.presentedViewController;
}

答案 2 :(得分:0)

我发现the accepted answer在紧凑模式下(例如iPhone)没有正确显示“完成”按钮,但在普通模式(例如iPad)中保持弹出状态。

以下代码是实现此功能的最低要求 - 将它们放在呈现视图控制器类中。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    UIViewController *dest = segue.destinationViewController;
    dest.popoverPresentationController.delegate = self;
}

- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style {
    UIViewController* presentedViewController = controller.presentedViewController;
    if ([controller isKindOfClass:[UIPopoverPresentationController class]] && style == UIModalPresentationFullScreen) {
        UINavigationController* navCtrl = [[UINavigationController alloc] initWithRootViewController:presentedViewController];
        UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismiss:)];
        presentedViewController.navigationItem.rightBarButtonItem = bbi;
        return navCtrl;
    }
    return presentedViewController;
}

-(IBAction)dismiss:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

注意与接受答案的三个不同之处:

  • 我们无需覆盖adaptivePresentationStyleForPresentationController:
  • 我们检查演示控制器是否为弹出框,但是请求全屏模式。
  • 我们返回一个新的导航控制器实例,而不是(错误地)将呈现的视图控制器转换为导航控制器。