Close button on adaptive popover

后端 未结 3 417
别跟我提以往
别跟我提以往 2021-02-05 11:42

In a storyboard I have a root view controller with a button which triggers a \'Present as Popover\' segue to a UINavigationController containing a UITableViewController. I want

相关标签:
3条回答
  • 2021-02-05 12:09

    Ok, I have managed to get it working. I think my problem was that the popoverPresentationController property traverses up the view controller heirarchy until it finds a view controller with a popoverPresentationController, i.e. if I have a view controller inside a navigation controller inside a popover the view controller popoverPresentationController would go to the nav controller and use it's property. For this to work, the view controller has to be a child of the navigation controller. At all the points I was trying to use the popoverPresentationController, this was not the case, e.g init, viewDidLoad, viewWillAppear. For some reason, willMoveToParentViewController is not called, even though didMove does get called. So I have no idea how to reference popoverPresentationController in a vc inside a nav controller before the ppc delegate methods are called.

    However, you can reference it in the presenting view controller in prepareForSegue, but you do need to explicitly tell it what presentation style to use. Here's my code that works when placed in the presenting view controller:

    - (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;
    }
    
    0 讨论(0)
  • 2021-02-05 12:18

    I found that the accepted answer doesn't correctly display a "done" button when in Compact mode (e.g. iPhone) but remain as popover in Regular mode (e.g. iPad).

    The following code is the bare minimum to make this work – place these in the presenting view controller class.

    -(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];
    }
    

    Notice the three differences with the accepted answer:

    • We don't need to override adaptivePresentationStyleForPresentationController:
    • We check whether the presentation controller is the popover but requesting full-screen mode instead.
    • We return a new navigation controller instance instead of (incorrectly) casting the presented view controller as a navigation controller.
    0 讨论(0)
  • 2021-02-05 12:19

    Here's the Swift version of Nick's correct answer for those who want a quick cut and paste.

    Note: This is to create a popover on your iPad but a modal sheet with a close button on your iPhone.

    In Xcode 6.3 storyboard, you hook up a view controller and designate the segue as a "Present as Popover"

    The below code should go in the view controller that segues to the popover, not in the popover itself:

    First you set up the popover delegate:

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

    Then you add the delegate extension and create the navigation controller / close button on the fly:

    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)
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题