UIPopoverPresentationController auf iOS 8 iPhone


75

Weiß jemand, ob UIPopoverPresentationControllerPopovers auf iPhones präsentiert werden können? Ich frage mich, ob Apple diese Funktion unter iOS 8 hinzugefügt hat, um einheitlichere Präsentations-Controller für iPad und iPhone zu erstellen.

Ich bin mir nicht sicher, ob es in Ordnung ist, Fragen aus der Beta zu stellen / zu beantworten. Ich werde es in diesem Fall entfernen.

Antworten:


84

Sie können das standardmäßige adaptive Verhalten ( UIModalPresentationFullScreenin einer kompakten horizontalen Umgebung, z. B. dem iPhone) mithilfe der über adaptivePresentationStyleForPresentationController:verfügbaren Methode überschreiben UIPopoverPresentationController.delegate.

UIPresentationControllerMit dieser Methode werden Sie aufgefordert, den neuen Präsentationsstil zu verwenden. In Ihrem Fall führt das einfache Zurückgeben UIModalPresentationNonedazu, dass das UIPopoverPresentationControllerFormat als Popover anstelle von Vollbild angezeigt wird.

Hier ist ein Beispiel für das Popover mit einem Segue-Setup im Storyboard von a UIBarButtonItembis " modal präsentieren " aUIViewController

class SomeViewController: UIViewController, UIPopoverPresentationControllerDelegate {

    // override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // swift < 3.0
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "PopoverSegue" {
            if let controller = segue.destinationViewController as? UIViewController {
                controller.popoverPresentationController.delegate = self
                controller.preferredContentSize = CGSize(width: 320, height: 186)                
            }
        }
    }

    // MARK: UIPopoverPresentationControllerDelegate

    //func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle { // swift < 3.0
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        // Return no adaptive presentation style, use default presentation behaviour
        return .None
    }
}

Dieser Trick wurde in der WWDC 2014-Sitzung 214 "View Controller Advancement in iOS8" (36:30) erwähnt.


2
Dies ist im GM für iPhone fehlerhaft. Wenn Sie versuchen zu präsentieren, während sich der Simulator im Hochformat befindet, ist er immer im Vollbildmodus. Wenn Sie in die Landschaft drehen, wird dies zu einem Popover. Wenn Sie wieder zum Hochformat zurückkehren, bleibt es ein Popover.
jjxtra

17
Die Lösung besteht darin, das Popover einzurichten, BEVOR Sie presentViewController aufrufen. Dies ist genau das Gegenteil von Apples Beispiel, in dem Sie ausdrücklich aufgefordert werden, das Popover einzurichten, nachdem Sie presentViewController aufgerufen haben.
jjxtra

4
Gleicher Code in obj-c für diejenigen, die Swift nicht lesen können: stackoverflow.com/a/28143620/1228075
Armin

@ PsychoDad ist richtig. Mein Sinn für Logik und Vertrauen brach zusammen. Vertrauen Sie niemandem, nicht einmal WWDC-Video und Apple-Klassenreferenz.
Daniel

@ Daniel in der Tat. Das Einstellen vor der Präsentation macht sowieso viel mehr Sinn, und es ist möglich, dass Apple dies geändert hat, bevor die Veröffentlichung veröffentlicht wurde.
jjxtra

75

Wenn jemand ein Popover nur mit Code präsentieren möchte, können Sie den folgenden Ansatz verwenden.

ZIEL C

Deklarieren Sie eine Eigenschaft von UIPopoverPresentationController:

@property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;

Verwenden Sie die folgende Methode, um das Popover von UIButton anzuzeigen:

- (IBAction)btnSelectDatePressed:(id)sender
{
    UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
    dateVC.preferredContentSize = CGSizeMake(280,200);
    destNav.modalPresentationStyle = UIModalPresentationPopover;
    _dateTimePopover8 = destNav.popoverPresentationController;
    _dateTimePopover8.delegate = self;
    _dateTimePopover8.sourceView = self.view;
    _dateTimePopover8.sourceRect = sender.frame;
    destNav.navigationBarHidden = YES;
    [self presentViewController:destNav animated:YES completion:nil];
}

Verwenden Sie die folgende Methode, um das Popover von UIBarButtonItem anzuzeigen:

- (IBAction)btnSelectDatePressed:(id)sender
{
    UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
    dateVC.preferredContentSize = CGSizeMake(280,200);
    destNav.modalPresentationStyle = UIModalPresentationPopover;
    _dateTimePopover8 = destNav.popoverPresentationController;
    _dateTimePopover8.delegate = self;
    _dateTimePopover8.sourceView = self.view;
     CGRect frame = [[sender valueForKey:@"view"] frame];
    frame.origin.y = frame.origin.y+20;
    _dateTimePopover8.sourceRect = frame;
    destNav.navigationBarHidden = YES;
    [self presentViewController:destNav animated:YES completion:nil];
}

Implementieren Sie diese Delegate-Methode auch in Ihrem View Controller:

- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
    return UIModalPresentationNone;
}

Um dieses Popover zu schließen, schließen Sie einfach den View Controller. Unten finden Sie den Code zum Schließen des View Controllers:

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

SCHNELL

Verwenden Sie die folgende Methode, um das Popover von UIButon anzuzeigen:

func filterBooks(sender: UIButon)
    {
        let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
        var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
        filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
        let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
        popoverPresentationViewController?.permittedArrowDirections = .Any
        popoverPresentationViewController?.delegate = self
        popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
        popoverPresentationViewController!.sourceView = self.view;
        popoverPresentationViewController!.sourceRect = sender.frame

        filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
        filterDistanceViewController.navigationBarHidden = true
        self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
    }

Verwenden Sie die folgende Methode, um das Popover von UIBarButtonItem anzuzeigen:

func filterBooks(sender: UIBarButtonItem)
    {
        let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
        var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
        filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
        let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
        popoverPresentationViewController?.permittedArrowDirections = .Any
        popoverPresentationViewController?.delegate = self
        popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
        popoverPresentationViewController!.sourceView = self.view;
        var frame:CGRect = sender.valueForKey("view")!.frame
        frame.origin.y = frame.origin.y+20
        popoverPresentationViewController!.sourceRect = frame

        filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
        filterDistanceViewController.navigationBarHidden = true
        self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
    }

Implementieren Sie diese Delegate-Methode auch in Ihrem View Controller:

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
        return .None
    }

UIPopoverPresentationControllerDelegateStellen Sie sicher, dass Sie den Delegaten in der Datei .h / .m / .swift hinzufügen


Dies funktionierte gut für mich auf dem iPhone im Querformat iOS8 / Swift
Leafcutter

1
Ich denke nicht, dass UIPopoverPresentationController deklariert werden muss. Es hat bei mir funktioniert, wenn ich einfach darauf zugegriffen und seine Eigenschaft über den Zielansichts-Controller festgelegt habe. Ich benutze Swift und Xcode 6.2.
Daniel

1
destNav.popoverPresentationController ist null.
Pronebird

Wenn Sie dieses Problem hatten, helfen Sie anderen Personen, indem Sie in der Dokumentation, in der Apple die Konfiguration des Popovers falsch beschreibt, auf die Schaltfläche " Feedback" klicken und vorschlagen, dass sie die Codeliste korrigieren.
Hwaxxer

1
Funktioniert nicht für meinen Fall: dateVC wird ohne Storyboard initialisiert
Loc

11

PROBLEM: Das iPhone-Popover zeigt den Vollbildmodus an und berücksichtigt den Wert für den bevorzugten Inhalt nicht.

LÖSUNG: Entgegen den Vorschlägen von Apple in der UIPopoverPresentationController-Klassenreferenz wird der View Controller angezeigt, nachdem ein Verweis auf den Popover Presentation Controller abgerufen und konfiguriert wurde.

// Get the popover presentation controller and configure it.
//...

// Present the view controller using the popover style.
[self presentViewController:myPopoverViewController animated: YES completion: nil]; 

Das Gleiche hier, die Implementierung des Delegaten und alles war nicht genug. Die Präsentation nach der Konfiguration machte den Trick auf dem iPhone 6S iOS 10.1
dvkch

Es ist nur wichtig, den Delegaten vor dem PresentViewController festzulegen.
BugaBuga


2

Ich habe eine Problemumgehung gefunden.

Verwenden Sie auf Xcode6.1 presentationController.delegateanstelle von popoverPresentationController.delegate.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier compare:@"showPopOver"] == NSOrderedSame) {
        UINavigationController * nvc = segue.destinationViewController;
        UIPresentationController * pc = nvc.presentationController;
        pc.delegate = self;
    }
}

#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

In WWDC 2014 "Controller-Verbesserungen in iOS8 anzeigen" können die folgenden Codes Popover auf dem iPhone anzeigen.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    UINavigationController * nvc = segue.destinationViewController;
    UIPopoverPresentationController * pvc = nvc.popoverPresentationController;
    pvc.delegate = self;
}

#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

Unter Xcode 6.1 zeigen diese Codes jedoch die Vollbilddarstellung an ... (nvc.popoverPresentationController ist null)

Ich bezweifle, dass es sich um einen Apple-Fehler handelt.


1

Verwenden Sie in iOS 8.3 und höher die folgende Syntax im UIPopoverPresentationControllerDelegateProtokoll, um die Popups zu überschreiben UIModalPresentationStyle.

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
    return .none
}

0

Fügen Sie diese beiden Methoden in Ihre WEBVIEW-Klasse ein. und hinzufügen

-(void) prepareForSegue: (UIStoryboardSegue * ) segue sender: (id) sender {
    // Assuming you've hooked this all up in a Storyboard with a popover presentation style
    if ([segue.identifier isEqualToString: @"showPopover"]) {
        UINavigationController * destNav = segue.destinationViewController;
        pop = destNav.viewControllers.firstObject;
        // This is the important part
        UIPopoverPresentationController * popPC = destNav.popoverPresentationController;
        popPC.delegate = self;
    }
}

- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
    return UIModalPresentationNone;
}

0

Sie können das UIPopoverPresentationControllerDelegate folgendermaßen erweitern:

protocol PopoverPresentationSourceView {}
extension UIBarButtonItem : PopoverPresentationSourceView {}
extension UIView : PopoverPresentationSourceView {}

extension UIPopoverPresentationControllerDelegate where Self : UIViewController {
   func present(popover: UIViewController, 
        from sourceView: PopoverPresentationSourceView, 
        size: CGSize, arrowDirection: UIPopoverArrowDirection) {

      popover.modalPresentationStyle = .popover
      popover.preferredContentSize = size
      let popoverController = popover.popoverPresentationController
      popoverController?.delegate = self
      if let aView = sourceView as? UIView {
          popoverController?.sourceView = aView
          popoverController?.sourceRect = CGRect(x: aView.bounds.midX, y: aView.bounds.midY, width: 0, height: 0)
      } else if let barButtonItem = sourceView as? UIBarButtonItem {
          popoverController?.barButtonItem = barButtonItem
      }
      popoverController?.permittedArrowDirections = arrowDirection
      present(popover, animated: true, completion: nil)
   }
}

Sie können jetzt present(popover: from: size: arrowDirection: )von jedem View Controller aus aufrufen , der UIPopoverPresentationControllerDelegatez.

class YourViewController : UIViewController {
    @IBAction func someButtonPressed(_ sender: UIButton) {
        let popover = SomeViewController()
        present(popover: popover, from: sender, size: CGSize(width: 280, height: 400), arrowDirection: .right)
    }
}

extension YourViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return .none
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.