73 votes

Comment rejeter un kangourou de la table de montage séquentiel

J'ai créé une liste à partir d'un UIBarButtonItem en utilisant Xcode Storyboards (donc il n'y a pas de code) comme ceci:

Xcode 5.0 Connections Inspector with Popover

La présentation de la liste fonctionne très bien. Cependant, je ne peux pas obtenir la liste à disparaître lorsque j'appuie sur l' UIBarButtonItem qui l'ont fait apparaître.

Lorsque le bouton est enfoncé (la première fois) la liste s'affiche. Lorsque le bouton est pressé de nouveau (une deuxième fois) de la même liste s'affiche au-dessus de lui, alors maintenant, j'ai deux popovers (ou plus si j'ai continuer en appuyant sur le bouton). Selon l' iOS Human Interface Guidelines j'ai besoin de faire la liste apparaissent sur la première frappe et de disparaître dans la seconde:

S'assurer qu'une seule liste est visible à l'écran à la fois. Vous ne devriez pas afficher plus d'une liste (ou affichage personnalisé conçu pour ressembler et se comporter comme une liste) en même temps. En particulier, vous devez éviter l'affichage d'une cascade ou la hiérarchie des popovers simultanément, dans lequel une liste émerge de l'autre.

Comment puis-je faire disparaître la liste lorsque l'utilisateur appuie sur l' UIBarButtonItem pour une deuxième fois?

114voto

rickster Points 19870

EDIT: Ces problèmes semblent être fixé iOS 7.1 / Xcode 5.1.1. (Peut-être plus tôt, comme je n'ai pas été en mesure de tester toutes les versions. Certainement après iOS 7.0, depuis que j'ai testé, ça.) Lorsque vous créez une liste des enchaînements à partir d'un UIBarButtonItem, la séquence permet de s'assurer que la récolte de la liste de nouveau masque la liste plutôt que de montrer un duplicata. Il fonctionne pour le nouveau UIPresentationController-en fonction liste enchaîne que Xcode 6 crée pour iOS 8, trop.

Depuis ma solution peut être d'intérêt historique à ceux qui soutiennent toujours plus tôt que les versions d'iOS, j'ai laissé ci-dessous.


Si vous stocker une référence à la séquence de la liste de contrôleur, de le rejeter avant de le définir une nouvelle valeur à répéter les invocations de l' prepareForSegue:sender:, tout ce que vous éviter, c'est le problème d'avoir plusieurs empilement popovers sur appuyer sur le bouton -- vous ne pouvez toujours pas utiliser le bouton pour fermer la fenêtre pop-over comme le HIG recommande (et comme on le voit dans Apple, les applications, etc.)

Vous pouvez profiter de l'ARC de la réinitialisation des références faibles pour une solution simple, si:

1: Segue à partir du bouton

Comme d'iOS 5, vous ne pouviez pas faire ce travail avec une séquence à partir d'un UIBarButtonItem, mais vous pouvez sur iOS 6 et versions ultérieures. (Sur iOS 5, vous avez de l'enchaîner à partir de la vue contrôleur lui-même, alors l'action du bouton d'appel performSegueWithIdentifier: après vérification de la liste.)

2: Utilisez une référence à la liste dans -shouldPerformSegue...

@interface ViewController
@property (weak) UIPopoverController *myPopover;
@end

@implementation ViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // if you have multiple segues, check segue.identifier
    self.myPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if (self.myPopover) {
        [self.myPopover dismissPopoverAnimated:YES];
        return NO;
    } else {
        return YES;
    }
}
@end

3: Il n'y a pas d'étape trois!

La bonne chose sur l'utilisation de la réduction à zéro la faiblesse de la référence ici est que, une fois que la liste contrôleur est rejeté -- si par programmation en shouldPerformSegueWithIdentifier:, ou automatiquement par l'utilisateur tapant quelque part d'autre en dehors de la liste -- le ivar va à l' nil nouveau, donc nous sommes de retour à notre état initial.

Sans réinitialisation de la faiblesse des références, nous aurions également à:

  • ensemble myPopover = nil lors du rejet en shouldPerformSegueWithIdentifier:, et
  • définir soi-même comme la liste du contrôleur de déléguer afin d'attraper popoverControllerDidDismissPopover: et aussi de mettre en myPopover = nil (nous avons donc les attraper quand la liste est automatiquement rejetée).

13voto

jorgecarreira Points 151

J’ai trouvé la solution ici http://stackoverflow.com/a/7938513/665396 en première prepareForSegue:sender : stocker dans une ivar/propriété le pointeur vers le UIPopoverController et l’utilisateur de ce pointeur pour faire disparaître le kangourou dans les appels ultérieurs.

2voto

J’ai utilisé custom segue pour cela.

1

créer personnalisé segue pour utiliser dans la table de montage séquentiel :

2

dans la vue contrôleur qui est source d’entrée/de segue par exemple démarrer segue avec action :

3

les références sont assignés par segue qui crée UIPopoverController - lorsque rejetant kangourou

Cordialement, Peter

2voto

Papick G. Taboada Points 412

Je l'ai résolu de la création d'une coutume ixPopoverBarButtonItem que soit déclenche la séquence ou rejette la liste affichée.

Ce que je fais: je bascule de l'action et de la cible du bouton, de sorte qu'il soit déclenche la séquence, ou en dispose, à l'heure actuelle liste.

Il m'a fallu beaucoup de googler pour cette solution, je ne veux pas prendre le générique de l'idée de basculement de l'action. Mettre le code dans un bouton personnalisé a été mon approche pour maintenir le code réutilisable à mon avis à un minimum.

Dans le storyboard, j'définir la classe de l'BarButtonItem de ma classe personnalisée:

custom bar button

Je passe alors la liste créé par l'enchaîner à mon bouton personnalisé de mise en œuvre dans l' prepareForSegue:sender: méthode:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender  
{
    if ([segue.identifier isEqualToString:@"myPopoverSegue"]) {
        UIStoryboardPopoverSegue* popSegue = (UIStoryboardPopoverSegue*)segue;
        [(ixPopoverBarButtonItem *)sender showingPopover:popSegue.popoverController];
    }
}

Btw... depuis je n'ai plus que l'un des boutons de déclenchement popovers, j'ai encore de conserver une référence de la liste actuellement affichée et la rejeter quand je fais un nouveau visible, mais ce n'était pas votre question...

Voici comment j'ai mis en place mon custom UIBarButtonItem:

...de l'interface:

@interface ixPopoverBarButtonItem : UIBarButtonItem

- (void) showingPopover:  (UIPopoverController *)popoverController;

@end

... et impl:

#import "ixPopoverBarButtonItem.h"
@interface ixPopoverBarButtonItem  ()
@property (strong, nonatomic) UIPopoverController *popoverController;
@property (nonatomic)         SEL                  tempAction;           
@property (nonatomic,assign)  id                   tempTarget; 

- (void) dismissPopover;

@end

@implementation ixPopoverBarButtonItem

@synthesize popoverController = _popoverController;
@synthesize tempAction = _tempAction;
@synthesize tempTarget = _tempTarget;

-(void)showingPopover:(UIPopoverController *)popoverController {

    self.popoverController = popoverController;
    self.tempAction = self.action;
    self.tempTarget = self.target;
    self.action = @selector(dismissPopover);
    self.target = self;
}    

-(void)dismissPopover {
    [self.popoverController dismissPopoverAnimated:YES];
    self.action = self.tempAction;
    self.target = self.tempTarget;

    self.popoverController = nil;
    self.tempAction = nil;
    self.tempTarget = nil;
}


@end

ps: je suis nouveau à l'ARC, donc je ne suis pas entièrement sûr si je suis une fuite ici. S'il vous plaît dites-moi si je suis...

2voto

Q80 Points 748

J’ai résolu ce problème sans avoir besoin de conserver une copie d’un `` . Tout simplement gérer tout dans la table de montage séquentiel (barre d’outils, BarButtons. etc.), et

  • gérer la visibilité de la kangourou par une valeur booléenne,
  • Assurez-vous qu’il y a un délégué, et il est réglé sur auto

Voici le code :

ViewController.h

ViewController.m

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X