【问题标题】:Close button on adaptive popover自适应弹出框上的关闭按钮
【发布时间】:2014-10-06 04:04:50
【问题描述】:

在情节提要中,我有一个带有按钮的根视图控制器,该按钮触发“作为弹出框呈现”到包含 UITableViewController 的 UINavigationController 的 segue。我希望导航控制器同时出现在 iPhone 和 iPad 上。

在 iPad 上,这在弹出窗口中效果很好。

在 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 上作为模态运行时也是如此。

【问题讨论】:

    标签: ios objective-c uikit uistoryboard


    【解决方案1】:

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

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

    在 Xcode 6.3 故事板中,您连接一个视图控制器并将 segue 指定为“Present as 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)
        }
    
    }
    

    【讨论】:

    • 这行得通!谢谢!在单独的说明中,如果不想手动处理“完成”一词的本地化,则可以使用此代码 :) let btnDone = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "dismiss") if
    • 很好的答案,这里是 Swift 4:Delegate: ``` override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.identifier == "myPopoverSegueName") { segue.目的地.popoverPresentationController?.delegate = self } } ```
    • Extension: ``` extension MyViewController: UIPopoverPresentationControllerDelegate { func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? { let leftButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissPopover)) let nav = UINavigationController(rootViewController: controller.presentedViewController) nav.topViewController?.navigationItem.leftBarButtonItem = leftButton return nav } } `` `
    • Dismiss: ``` @objc private funcdismissPopover() {dismiss(animated: true, completion: nil) } ``` 抱歉格式化。我现在不能花更多时间在这上面......
    【解决方案2】:

    好的,我已经设法让它工作了。我认为我的问题是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;
    }
    

    【讨论】:

    • 在新的多任务 iOS9 世界中,它可以从紧凑切换回常规宽度 - 那么如何随后删除完成按钮?
    • 它会自动从紧凑(模态)切换到常规(弹出框)演示吗?如果没有,那么我认为这仍然可以正常工作。如果它确实过渡,您可以设置或删除- willTransitionToTraitCollection:withTransitionCoordinator:中的条形按钮项
    • 不错的解决方案。但是,如果您想在情节提要中设置完成按钮和UINavigationController,您可以使用navigationBarHidden 属性在紧凑环境中显示栏并在情节提要中默认隐藏它。
    • @Scotty 你对这个问题的多任务处理有什么看法?
    【解决方案3】:

    我发现the accepted answer 在紧凑模式(例如 iPhone)下无法正确显示“完成”按钮,但在常规模式(例如 iPad)下仍保持弹出窗口。

    以下代码是完成这项工作的最低要求——将它们放在 presenting 视图控制器类中。

    -(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:
    • 我们检查演示控制器是否是弹出框但请求全屏模式。
    • 我们返回一个新的导航控制器实例,而不是(错误地)将呈现的视图控制器转换为导航控制器。

    【讨论】:

      猜你喜欢
      • 2014-02-26
      • 2012-12-21
      • 1970-01-01
      • 1970-01-01
      • 2012-12-28
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 2014-01-19
      相关资源
      最近更新 更多