web-dev-qa-db-fra.com

iOS9 popover pointe toujours vers le coin supérieur gauche de l'ancre

J'utilise un scénario de storyboard qui présente un contrôleur de vue comme popover. Le seque a pour coutume une variable UIView. Sur les versions antérieures à iOS9, la fenêtre popover pointait correctement vers le bas au centre de la variable UIView personnalisée (présentée sous UIView). Sur iOS9, il pointe vers le coin supérieur gauche de la UIView.

J'ai essayé de retrouver tous les appels de sélecteur dans la variable personnalisée UIView pour savoir si je devais implémenter quelque chose que je devais implémenter dans ma variable personnalisée UIView afin de fournir le "point d'accès" pour le popover, mais je n'ai rien trouvé

Des idées..? Merci

_ {Merci à @Igor Camilo pour sa réponse - au cas où cela serait utile à certains, voici comment j'ai corrigé cela dans mon code} _:

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

     UIPopoverPresentationController* possiblePopOver = segue.destinationViewController.popoverPresentationController;
     if (possiblePopOver != nil) {
         //
         // iOS9 -- ensure correct sourceRect
         //
         possiblePopOver.sourceRect = possiblePopOver.sourceView.bounds;
     }
    ...
 }

_ {Exemple: Le bouton 'Court' déclenche un popover, le popover pointe sur le coin supérieur gauche du contrôle 'Trier'

 Resulting popover

 Segue settings

31
Nikos

J'ai eu exactement le même problème. Je viens de le résoudre en définissant sourceRect dans prepareForSegue:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    switch segue.identifier {
    case "Popover Identifier"?:
        if #available(iOS 9.0, *) {
            segue.destinationViewController?.popoverPresentationController?.sourceRect = anchorView.bounds
        }
    default:
        break
    }
}
32
Igor Camilo

J'avais le même problème, mais mon application comportait une multitude de fenêtres publicitaires intempestives. J'ai donc créé une fonction centralisée pour le correctif (mais je devais quand même l'utiliser sur tous les contrôleurs de vue dotés de fenêtres contextuelles). 

// Fix for IOS 9 pop-over arrow anchor bug
// ---------------------------------------
// - IOS9 points pop-over arrows on the top left corner of the anchor view
// - It seems that the popover controller's sourceRect is not being set
//   so, if it is empty  CGRect(0,0,0,0), we simply set it to the source view's bounds
//   which produces the same result as the IOS8 behaviour.
// - This method is to be called in the prepareForSegue method override of all
//   view controllers that use a PopOver segue
//
//   example use:
//
//          override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
//          {
//             fixIOS9PopOverAnchor(segue)   
//          }
//      
extension UIViewController
{
   func fixIOS9PopOverAnchor(segue:UIStoryboardSegue?)
   {
      guard #available(iOS 9.0, *) else { return }          
      if let popOver = segue?.destinationViewController.popoverPresentationController,
         let anchor  = popOver.sourceView
         where popOver.sourceRect == CGRect()      
            && segue!.sourceViewController === self 
      { popOver.sourceRect = anchor.bounds }   
   }       
}
18
Alain T.

Voici un exemple d'extrait de code d'Igor Camilo dans Objective-C.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // If the sender is a UIView, we might have to correct the sourceRect of
    // a potential popover being presented due to an iOS 9 bug. See:
    // https://openradar.appspot.com/22095792 and http://stackoverflow.com/a/32698841/368674
    if ([sender isKindOfClass:UIView.class]) {
        // Fetch the destination view controller
        UIViewController *destinationViewController = [segue destinationViewController];

        // If there is indeed a UIPopoverPresentationController involved
        if ([destinationViewController respondsToSelector:@selector(popoverPresentationController)]) {
            // Fetch the popover presentation controller
            UIPopoverPresentationController *popoverPresentationController =
            destinationViewController.popoverPresentationController;

            // Set the correct sourceRect given the sender's bounds
            popoverPresentationController.sourceRect = ((UIView *)sender).bounds;
        }
    }
}
8
zath

Voici ma solution, dans prepareForSegue:

segue.destinationViewController.popoverPresentationController?.sourceRect = CGRectMake(anchorView.frame.size.width/2, anchorView.frame.size.height, 0, 0)

Cela déplacera le pointeur vers le bas au milieu de la vue d'ancrage

7
s0m3chill

J'ai également rencontré ce problème, mais cela fonctionne maintenant lorsque je l'ai ajouté à ma PrepareForSegue Étant donné que mon identifiant Segue contient la chaîne Popover

if ([[segue identifier] containsString:@"Popover"]) {
    [segue destinationViewController].popoverPresentationController.sourceRect = self.navigationItem.titleView.bounds;
}
1
bravehart_sf

Si vous faites référence à votre popover UIViewController dans votre UIViewController principale, vous pouvez ajuster la propriété sourceRect pour compenser le popover. Par exemple, étant donné popover popoverVC, vous pouvez faire quelque chose comme ceci:

float xOffset = 10.0;
float yOffset = 5.0;
popoverVC.popoverPresentationController.sourceRect = CGMakeRect(xOffset, yOffset, 0.0, 0.0);
0
Chris Stillwell

Une réponse un peu plus récente pour Swift 3! Pardonner tout le casting 

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "popSegue" {
            let popoverViewController = segue.destination
            popoverViewController.popoverPresentationController?.delegate = self
            segue.destination.popoverPresentationController?.sourceRect = ((sender as? UIButton)?.bounds)!
        }
    }
0
Matt Bart

juste pour mettre à jour un exemple réel avec un code de travail pour tout UIView

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch segue.identifier {
    case "PopoverSegueId"?:
        if #available(iOS 9.0, *) {
            segue.destination.popoverPresentationController?.sourceRect = (segue.destination.popoverPresentationController?.sourceView?.bounds)!
        }
    default:
        break
    }

}
0
J Mustermann

Essayez de définir la largeur et la hauteur de votre ancre source (UIView ou UIBarButtonItem) et réglez-le sur actif. Définissez-le lorsque vous initialisez UIView ou UIBarButtonItem.

UIBarButtonItem

 [[youruibarbuttonitem.customView.widthAnchor constraintEqualToConstant:youruibarbuttonitem.customView.bounds.size.width] setActive:YES];
 [[youruibarbuttonitem.customView.heightAnchor constraintEqualToConstant:youruibarbuttonitem.customView.bounds.size.height] setActive:YES];

UIView

[[uiview.widthAnchor constraintEqualToConstant:uiview.bounds.size.width] setActive:YES];
 [[uiview.heightAnchor constraintEqualToConstant:uiview.bounds.size.height] setActive:YES];
0
Tanvir Singh