Comment présenter correctement le popover dans iOS 8

118

J'essaie d'ajouter un UIPopoverView à mon application Swift iOS 8, mais je ne parviens pas à accéder à la propriété PopoverContentSize, car le popover ne s'affiche pas dans la forme correcte. mon 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)
}

production:

entrez la description de l'image ici

Quand je fais la même chose via UIPopoverPresentationController, je ne le fais toujours pas. c'est mon 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)

}

J'obtiens exactement le même résultat.

Comment personnaliser la taille de mon popover? Toute aide serait très appréciée!

Joris416
la source
Il y a une vidéo WWDC sur le site du développeur intitulée "A Look Inside Presentation Controller" Elle explique comment utiliser le UIPopoverPresentationController
Wextux
J'ai édité ma question en fonction de la vidéo Apple concernant le contrôleur UIpopoverpresentationctontroller, mais rien n'a changé! voyez-vous peut-être quelque chose que je devrais changer à ce sujet? Merci pour votre contribution!
Joris416

Réponses:

148

D'accord, un colocataire y a jeté un coup d'œil et l'a compris:

 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)

}

C'est comme ça.

Vous ne parlez plus au popover lui-même, vous parlez au contrôleur de vue à l'intérieur pour définir la taille du contenu, en appelant la propriété preferredContentSize

Joris416
la source
15
C'est probablement l'évidence, mais ce n'est pas seulement lié à la rapidité. Je devais aussi le faire dans mon application obj-c :)
Kevin R
4
Un autre commentaire sur le code - vous pouvez utiliser "let" au lieu de "var". Apple le recommande pour les cas où vous n'avez pas besoin de réaffecter la valeur.
EPage_Ed
3
Ceci est buggé dans le GM pour iPhone. Si vous essayez de présenter pendant que le simulateur est en mode portrait, il est toujours en plein écran. Si vous faites pivoter en paysage, cela devient un popover. Si vous revenez au portrait, il reste un popover.
jjxtra
1
La solution consiste à configurer le popover AVANT d'appeler presentViewController. C'est exactement le contraire de l'exemple d'Apple où ils vous disent explicitement de configurer le popover APRÈS avoir appelé presentViewController.
jjxtra
1
@PsychoDad peut vous fournir un lien vers cette solution que vous avez mentionnée. Je suis toujours bloqué sur "alors que le simulateur est en portrait, il est toujours en plein écran". Merci
Nishant
53

En fait, c'est beaucoup plus simple que cela. Dans le storyboard, vous devez créer le viewcontroller que vous souhaitez utiliser comme popover et créer une classe viewcontroller pour lui comme d'habitude. Faites une séquence comme indiqué ci-dessous à partir de l'objet que vous souhaitez ouvrir le popover, dans ce cas le UIBarButtonnommé "Config".

entrez la description de l'image ici

Dans le "contrôleur de vue mère", implémentez la UIPopoverPresentationControllerDelegateméthode et la méthode déléguée:

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

Remplacez la prepareForSequeméthode comme ceci:

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)
        }
    }
}

Et tu as fini. Et vous pouvez maintenant traiter la vue popover comme n'importe quelle autre vue, c'est-à-dire. ajouter des champs et que sais-je! Et vous obtenez le contrôleur de contenu en utilisant la popoverPresentationController.presentedViewControllerméthode du UIPopoverPresentationController.

Également sur un iPhone, vous devrez écraser

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

        return UIModalPresentationStyle.none
    } 
user1700737
la source
28

J'ai trouvé un exemple complet de la façon dont tout cela fonctionne afin que vous puissiez toujours afficher un popover quel que soit le périphérique / l'orientation https://github.com/frogcjn/AdaptivePopover_iOS8_Swift .

La clé est d'implémenter UIAdaptivePresentationControllerDelegate

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

Puis prolongez l'exemple ci-dessus (d'Imagine Digital):

nav.popoverPresentationController!.delegate = implOfUIAPCDelegate
David Hunt
la source
J'utilise UIPopoverPresentationControllerDelegate
onmyway133
3
Correct, UIPopoverPresentationControllerDelegate étend UIAdaptivePresentationControllerDelegate. Ainsi, par définition, les deux contiennent la méthode «adaptivePresentationStyleForPresentationController». J'ai fourni l'interface de base car c'est là que la méthode est documentée dans les documents d'API d'Apple.
David Hunt
1
Notez qu'il s'agit d'un comportement non documenté. Le document dit que cette méthode de délégué doit retourner "soit UIModalPresentationFullScreenou UIModalPresentationOverFullScreen". En outre, «Si vous n'implémentez pas cette méthode ou ne renvoyez aucun style autre que UIModalPresentationFullScreenou UIModalPresentationOverFullScreen, le contrôleur de présentation ajuste le style de présentation au UIModalPresentationFullScreenstyle».
Tom
1
La documentation actuelle indique qu'à partir d'iOS 8.3, vous devez utiliser - adaptivePresentationStyleForPresentationController: traitCollection: et que le style renvoyé doit être «UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet ou UIModalPresentationNone».
Dale
25

Swift 2.0

Eh bien, j'ai travaillé. Regarde. Création d'un ViewController dans StoryBoard. Associé à la classe PopOverViewController.

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)
    }
}      

Voir 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
    }
}  

Remarque: La méthode func showPopover (base: UIView) doit être placée avant ViewDidLoad. J'espère que ça aide !

AG
la source
salut @Alvin, je vais afficher une vue de l'annotation de la carte. alors j'ai fait la même chose que toi. la différence est que je vais remplir tableviewcontroller au lieu de view. Maintenant, le problème ne touche pas la méthode déléguée. "PopoverPresentationControllerDidDismissPopover". quand je quitte le contrôleur. pouvez-vous aider? (La question n'est pas liée au poste)
Subin K Kuriakose
1
Pourquoi une showPopover(base: UIView)méthode devrait-elle être placée avant viewDidLoad()?
Eimantas
15

Dans iOS9, UIPopoverController est déprécié. Vous pouvez donc utiliser le code ci-dessous pour la version Objective-C ci-dessus 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]; }
Vijay
la source
La question demande spécifiquement Swift, pas Objective-C.
Eric Aya
8

Ici, je convertis le code Swift "Joris416" en 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;
}

N'oubliez pas d'ajouter
UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate

user2941395
la source
La question demande spécifiquement Swift, pas Objective-C.
Eric Aya
4

Ceci est mieux expliqué sur le blog quotidien iOS8

En bref, une fois que vous avez défini le modalPresentationStyle de votre UIViewController sur .Popover, vous pouvez obtenir une UIPopoverPresentationClass (une nouvelle classe iOS8) via la propriété popoverPresentationController du contrôleur.

Clafou
la source
3

J'ai créé une version Objective-C de la réponse rapide Imagine Digitals ci-dessus. Je ne pense pas avoir manqué quoi que ce soit car il semble fonctionner sous les tests préliminaires, si vous repérez quelque chose, faites-le moi savoir, et je le mettrai à jour

-(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];
}
Narco
la source
Je pense que vous avez laissé de côté popover.sourceView = self.view;
ghr
La question demande spécifiquement Swift, pas Objective-C.
Eric Aya
4
Je m'en rends compte, mais google vous amène ici même si vous recherchez objectif-C. C'est comme ça que j'ai fini ici.
narco
3

mes deux cents pour 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
}

et expérimentez dans:

func adaptivePresentationStyle ...

    return .popover

ou: retournez .pageSheet .... et ainsi de suite ..

ingconti
la source
2

Implémentez UIAdaptivePresentationControllerDelegate dans votre Viewcontroller. Puis ajouter :

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

Ce qui suit contient un guide assez complet sur la configuration et la présentation des popovers. https://www.appcoda.com/presentation-controllers-tutorial/

En résumé, une implémentation viable (avec quelques mises à jour de la syntaxe de l'article d'origine pour Swift 4.2 ), qui sera ensuite appelée depuis ailleurs, serait quelque chose comme ceci:

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)
}

Une grande partie de cela a déjà été abordée dans la réponse de @mmc, mais l'article aide à expliquer certains de ces éléments de code utilisés et montre également comment il pourrait être développé.

Il fournit également de nombreux détails supplémentaires sur l'utilisation de la délégation pour gérer le style de présentation pour iPhone par rapport à iPad, et pour permettre le rejet du popover s'il est déjà affiché en plein écran. Encore une fois, mis à jour pour 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)
}

J'espère que cela t'aides.

TheNeil
la source
0

Pour ceux qui veulent étudier!

J'ai créé un projet Open Source pour ceux qui veulent étudier et utiliser la vue Popover à des fins. Vous pouvez trouver le projet ici. https://github.com/tryWabbit/KTListPopup

KTListNewResize

essayezKuldeepTanwar
la source