代码之家  ›  专栏  ›  技术社区  ›  Nick

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

  •  17
  • Nick  · 技术社区  · 10 年前

    在一个故事板中,我有一个根视图控制器,它带有一个按钮,该按钮会触发一个“显示为弹出窗口”的segue到一个包含UITableViewController的UINavigationController。我希望导航控制器同时出现在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上作为模态运行时也是如此。

    3 回复  |  直到 10 年前
        1
  •  15
  •   Travis M.    7 年前

    这是斯威夫特版本的尼克正确答案,适合那些想要快速剪切和粘贴的人。

    注意:这是为了在iPad上创建弹出窗口,但在iPhone上创建带有关闭按钮的模式表。

    在Xcode 6.3情节提要中,您连接一个视图控制器,并将segue指定为“Present as 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)
        }
    
    }
    
        2
  •  12
  •   Dharmesh Dhorajiya    10 年前

    好的,我已经设法让它工作了。我想我的问题是 popoverPresentationController 属性向上遍历视图控制器层次结构,直到找到具有 弹出显示控件 ,即,如果我在视图控制器的弹出窗口中的导航控制器中有一个视图控制器 弹出显示控件 会去导航控制器并使用它的属性。要使其工作,视图控制器必须是导航控制器的子级。在所有的时候,我都试图使用 弹出显示控件 事实并非如此 init , viewDidLoad , viewWillAppear 出于某种原因, willMoveToParentViewController 尽管 didMove 确实会被呼叫。所以我不知道如何引用 弹出显示控件 在调用ppc委托方法之前,在nav控制器内的vc中。

    然而 ,可以在演示视图控制器中引用它 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;
    }
    
        3
  •  0
  •   Community CDub    8 年前

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