So präsentieren Sie Popover in iOS 8 richtig


118

Ich versuche, meiner Swift iOS 8-App eine UIPopoverView hinzuzufügen, kann jedoch nicht auf die PopoverContentSize-Eigenschaft zugreifen, da das Popover nicht in der richtigen Form angezeigt wird. Mein Code:

var popover: UIPopoverController? = nil 

    func addCategory() {

    var newCategory = storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: newCategory)
    popover = UIPopoverController(contentViewController: nav)
    popover!.setPopoverContentSize(CGSizeMake(550, 600), animated: true)
    popover!.delegate = self
    popover!.presentPopoverFromBarButtonItem(self.navigationItem.rightBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}

Ausgabe:

Geben Sie hier die Bildbeschreibung ein

Wenn ich dasselbe über UIPopoverPresentationController mache, bekomme ich es immer noch nicht fertig. Das ist mein Code:

func addCategory() {

    var popoverContent = self.storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController as UIPopoverPresentationController
    popover.delegate = self
    popover.popoverContentSize = CGSizeMake(1000, 300)
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Ich bekomme genau die gleiche Ausgabe.

Wie passe ich die Größe meines Popovers an? Jede Hilfe wäre sehr dankbar!


Auf der Entwicklerseite gibt es ein WWDC-Video mit dem Titel "Ein Blick in Präsentationscontroller". Es erklärt, wie der UIPopoverPresentationController
Wextux

Ich habe meine Frage gemäß dem Apple-Video zum UIpopoverpresentationctontroller bearbeitet, aber nichts hat sich geändert! Sehen Sie vielleicht etwas, das ich daran ändern sollte? Vielen Dank für die Eingabe!
Joris416

Antworten:


148

Okay, ein Mitbewohner hat es sich angesehen und herausgefunden:

 func addCategory() {

    var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController
    popoverContent.preferredContentSize = CGSizeMake(500,600)
    popover.delegate = self
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Das ist der Weg.

Sie sprechen nicht mehr mit dem Popover selbst, sondern mit dem darin enthaltenen Ansichts-Controller, um die Inhaltsgröße festzulegen, indem Sie die Eigenschaft aufrufen preferredContentSize


15
Wahrscheinlich das Offensichtliche, aber das hängt nicht nur schnell zusammen. Ich musste dies auch in meiner obj-c App tun :)
Kevin R

4
Noch ein Kommentar zum Code - Sie können "let" anstelle von "var" verwenden. Apple empfiehlt es für Fälle, in denen Sie den Wert nicht neu zuweisen müssen.
EPage_Ed

3
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

1
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

1
@PsychoDad können Sie bitte Link zu dieser Lösung, die Sie erwähnt haben. Ich stecke immer noch fest bei "Während der Simulator im Hochformat ist, ist er immer im Vollbildmodus". Danke
Nishant

53

Eigentlich ist es viel einfacher als das. Im Storyboard sollten Sie den Viewcontroller, den Sie als Popover verwenden möchten, erstellen und wie gewohnt eine Viewcontroller-Klasse dafür erstellen. Machen Sie einen Übergang wie unten gezeigt von dem Objekt, das Sie das Popover öffnen möchten, in diesem Fall den UIBarButtonNamen "Config".

Geben Sie hier die Bildbeschreibung ein

Implementieren Sie im "Mother Viewcontroller" die UIPopoverPresentationControllerDelegateund die Delegate-Methode:

func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
    //do som stuff from the popover
}

Überschreiben Sie die prepareForSequeMethode wie folgt :

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     //segue for the popover configuration window
    if segue.identifier == "yourSegueIdentifierForPopOver" {
        if let controller = segue.destinationViewController as? UIViewController {
            controller.popoverPresentationController!.delegate = self
            controller.preferredContentSize = CGSize(width: 320, height: 186)
        }
    }
}

Und du bist fertig. Und Sie können die Popover-Ansicht jetzt wie jede andere Ansicht behandeln, z. Felder hinzufügen und was nicht! Und Sie erhalten den Content-Controller mithilfe der popoverPresentationController.presentedViewControllerMethode in der UIPopoverPresentationController.

Auch auf einem iPhone müsste man überschreiben

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {

        return UIModalPresentationStyle.none
    } 

28

Ich habe ein vollständiges Beispiel gefunden, wie dies alles funktioniert, damit Sie unabhängig von Gerät / Ausrichtung immer ein Popover anzeigen können . Https://github.com/frogcjn/AdaptivePopover_iOS8_Swift .

Der Schlüssel ist die Implementierung von UIAdaptivePresentationControllerDelegate

func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle {
    // This *forces* a popover to be displayed on the iPhone
    return .None
}

Erweitern Sie dann das obige Beispiel (von Imagine Digital):

nav.popoverPresentationController!.delegate = implOfUIAPCDelegate

Ich benutze UIPopoverPresentationControllerDelegate
onmyway133

3
Richtig, UIPopoverPresentationControllerDelegate erweitert UIAdaptivePresentationControllerDelegate. Per Definition enthalten beide also die Methode 'adaptivePresentationStyleForPresentationController'. Ich habe die Basisschnittstelle bereitgestellt, da dort die Methode in Apples API-Dokumenten dokumentiert ist.
David Hunt

1
Beachten Sie, dass dies ein undokumentiertes Verhalten ist. Das Dokument sagt, dass diese Delegatenmethode "entweder UIModalPresentationFullScreenoder UIModalPresentationOverFullScreen" zurückgeben muss. "Wenn Sie diese Methode nicht implementieren oder einen anderen Stil als UIModalPresentationFullScreenoder zurückgeben UIModalPresentationOverFullScreen, passt der Präsentationscontroller den Präsentationsstil an den UIModalPresentationFullScreenStil an."
Tom

1
In der aktuellen Dokumentation wird empfohlen, ab iOS 8.3 Folgendes zu verwenden: adaptivePresentationStyleForPresentationController: traitCollection: Der zurückgegebene Stil muss "UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet oder UIModonePesent" sein.
Dale

25

Swift 2.0

Nun, ich habe es geschafft. Guck mal. In StoryBoard einen ViewController erstellt. Verbunden mit der PopOverViewController-Klasse.

import UIKit

class PopOverViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()    
        self.preferredContentSize = CGSizeMake(200, 200)    
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")    
    }    
    func dismiss(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}      

Siehe ViewController:

//  ViewController.swift

import UIKit

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
{
    func showPopover(base: UIView)
    {
        if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {    

            let navController = UINavigationController(rootViewController: viewController)
            navController.modalPresentationStyle = .Popover

            if let pctrl = navController.popoverPresentationController {
                pctrl.delegate = self

                pctrl.sourceView = base
                pctrl.sourceRect = base.bounds

                self.presentViewController(navController, animated: true, completion: nil)
            }
        }
    }    
    override func viewDidLoad(){
        super.viewDidLoad()
    }    
    @IBAction func onShow(sender: UIButton)
    {
        self.showPopover(sender)
    }    
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return .None
    }
}  

Hinweis: Die func showPopover-Methode (Basis: UIView) sollte vor ViewDidLoad platziert werden. Ich hoffe es hilft !


hi @Alvin, ich werde eine Ansicht aus der Kartenanmerkung öffnen. Also habe ich das Gleiche getan wie du. Der Unterschied besteht darin, dass der Tableviewcontroller anstelle der Ansicht ausgefüllt wird. Jetzt trifft das Problem nicht die Delegatenmethode "popoverPresentationControllerDidDismissPopover". wenn ich den Controller entlasse. kannst du helfen ? (Frage hat nichts mit dem Beitrag zu
tun

1
Warum sollte eine showPopover(base: UIView)Methode vorher platziert werden viewDidLoad()?
Eimantas

15

In iOS9 wird UIPopoverController abgeschrieben. Verwenden Sie also den folgenden Code für die Objective-C-Version über iOS9.x.

- (IBAction)onclickPopover:(id)sender {
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
UIViewController *viewController = [sb instantiateViewControllerWithIdentifier:@"popover"];

viewController.modalPresentationStyle = UIModalPresentationPopover;
viewController.popoverPresentationController.sourceView = self.popOverBtn;
viewController.popoverPresentationController.sourceRect = self.popOverBtn.bounds;
viewController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:viewController animated:YES completion:nil]; }

Die Frage fragt speziell nach Swift, nicht nach Objective-C.
Eric Aya

8

Hier konvertiere ich "Joris416" Swift Code in Objective-c,

-(void) popoverstart
{
    ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"PopoverView"];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:controller];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController *popover = nav.popoverPresentationController;
    controller.preferredContentSize = CGSizeMake(300, 200);
    popover.delegate = self;
    popover.sourceView = self.view;
    popover.sourceRect = CGRectMake(100, 100, 0, 0);
    popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
    [self presentViewController:nav animated:YES completion:nil];
}

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

Denken Sie daran, hinzuzufügen
UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate


Die Frage fragt speziell nach Swift, nicht nach Objective-C.
Eric Aya

4

Dies wird am besten im täglichen iOS8-Blog erklärt

Kurz gesagt, sobald Sie den modalPresentationStyle Ihres UIViewController auf .Popover festgelegt haben, können Sie über die Eigenschaft popoverPresentationController des Controllers eine UIPopoverPresentationClass (eine neue iOS8-Klasse) abrufen.


3

Ich habe oben eine Objective-C-Version von Imagine Digitals schnell beantwortet. Ich glaube nicht, dass ich etwas verpasst habe, da es unter vorläufigen Tests zu funktionieren scheint. Wenn Sie etwas entdecken, lassen Sie es mich wissen und ich werde es aktualisieren

-(void) presentPopover
{
    YourViewController* popoverContent = [[YourViewController alloc] init]; //this will be a subclass of UIViewController
    UINavigationController* nav =  [[UINavigationController alloc] initWithRootViewController:popoverContent];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController* popover = nav.popoverPresentationController;
    popoverContent.preferredContentSize = CGSizeMake(500,600);
    popover.delegate = self;
    popover.sourceRect = CGRectMake(100,100,0,0); //I actually used popover.barButtonItem = self.myBarButton;

    [self presentViewController:nav animated:YES completion:nil];
}

Ich denke, Sie haben ausgelassen popover.sourceView = self.view;
ghr

Die Frage fragt speziell nach Swift, nicht nach Objective-C.
Eric Aya

4
Mir ist das klar, aber Google bringt Sie hierher, auch wenn Sie nach Ziel-C suchen. So bin ich hier gelandet.
Narco

3

meine zwei Cent für Xcode 9.1 / Swift 4.

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

    override func viewDidLoad(){
        super.viewDidLoad()

        let when = DispatchTime.now() + 0.5

        DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in
            // to test after 05.secs... :)
            self.showPopover(base: self.view)

        })

}


func showPopover(base: UIView) {
    if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "popover") as? PopOverViewController {

        let navController = UINavigationController(rootViewController: viewController)
        navController.modalPresentationStyle = .popover

        if let pctrl = navController.popoverPresentationController {
            pctrl.delegate = self

            pctrl.sourceView = base
            pctrl.sourceRect = base.bounds

            self.present(navController, animated: true, completion: nil)
        }
    }
}


@IBAction func onShow(sender: UIButton){
    self.showPopover(base: sender)
}

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

und experimentieren in:

func adaptivePresentationStyle ...

    return .popover

oder: return .pageSheet .... und so weiter ..


2

Implementieren Sie UIAdaptivePresentationControllerDelegate in Ihrem Viewcontroller. Dann füge hinzu :

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

1

Im Folgenden finden Sie eine ziemlich umfassende Anleitung zum Konfigurieren und Präsentieren von Popovers. https://www.appcoda.com/presentation-controllers-tutorial/

Zusammenfassend wäre eine praktikable Implementierung (mit einigen Aktualisierungen der ursprünglichen Artikelsyntax für Swift 4.2 ), die dann von einer anderen Stelle aufgerufen werden könnte, wie folgt:

func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
    popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
    if let popoverController = popoverViewController.popoverPresentationController {
        popoverController.delegate = self
        popoverController.sourceView = originView
        popoverController.sourceRect = originView.bounds
        popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
    }
    self.present(popoverViewController, animated: true)
}

Vieles davon wurde bereits in der Antwort von @mmc behandelt, aber der Artikel hilft dabei, einige der verwendeten Codeelemente zu erläutern und zu zeigen, wie sie erweitert werden können.

Es enthält außerdem viele zusätzliche Details zur Verwendung der Delegierung, um den Präsentationsstil für iPhone und iPad zu verwalten und das Popover zu schließen, falls es jemals im Vollbildmodus angezeigt wird. Wieder aktualisiert für Swift 4.2 :

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

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    if traitCollection.horizontalSizeClass == .compact {
        return UIModalPresentationStyle.none
        //return UIModalPresentationStyle.fullScreen
    }
    //return UIModalPresentationStyle.fullScreen
    return UIModalPresentationStyle.none
}

func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
    switch style {
    case .fullScreen:
        let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneWithPopover))
        navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton
        return navigationController
    default:
        return controller.presentedViewController
    }
}

// As of Swift 4, functions used in selectors must be declared as @objc
@objc private func doneWithPopover() {
    self.dismiss(animated: true, completion: nil)
}

Hoffe das hilft.


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.