web-dev-qa-db-fra.com

Comment "annuler" un UIStoryBoardSegue

Est-ce que quelqu'un sait comment "arrêter" une transition de transition conditionnellement:

Mes cellules de vue de tableau représentent des produits qui peuvent être visualisés dans une vue "détaillée" descendante ... ou pas! (Cela dépend de quelques choses)

Maintenant, mon application considère tous les produits "déverrouillés":

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
    ListaProdottiController *prodottiViewController = [segue destinationViewController];
    prodottiViewController.blocco = [self.fetchedResultsController objectAtIndexPath:selectedRowIndex];
}

Comment puis-je annuler la sélection de ligne => drilldown, à ce stade?

43
Fabio B.

Si vous ciblez iOS 6 ou une version ultérieure, ma connaissance de la façon la plus propre de le faire est la suivante:

-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    if([identifier isEqualToString:@"show"])
    {
        NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
        Blocco *blocco = [self.fetchedResultsController objectAtIndexPath:selectedRowIndex];
        return [blocco meetRequiredConditions];
    }
    return YES;
}

Là où il y a une méthode

-(BOOL) meetsRequiredConditions;

Défini sur votre classe Blocco renvoie OUI si le "couple de choses" qui permettent un zoom avant sont valides.

79
Joshcodes

Je ne sais pas si c'est la bonne façon de le faire, mais j'ai découvert une solution de contournement.

À partir du storyboard, j'associe (contrôle + clic) une séquence de la barre d'état dans le contrôleur de vue. Donnez au segue un ID (par exemple: switchSegue).

Maintenant, à partir d'une action dans votre code (dans mon code j'utilise un bouton), j'appelle:

 [self performSegueWithIdentifier:@"switchSegue" sender:sender];

De cette façon, vous pouvez contrôler si votre enchaînement est effectué ou non. Essayez des tutoriels qui m'ont aidé de ici et ici

J'espère que cela t'aides.

32
igbopie

J'utilise une approche beaucoup plus facile et ordonnée.

Storyboard

  1. Créez deux cellules identiques avec des identifiants différents. Par exemple: "cellWithSegue" et "cellWithoutSegue".
  2. Connectez la première cellule ("cellWithSegue") à la séquence que vous souhaitez afficher.
  3. Ne connectez la deuxième cellule à aucune séquence.

Vue tablea

  1. Sur cellForRowAtIndexPath, implémentez une logique pour déterminer si la cellule doit être liée à un enchaînement ou non.
  2. Pour les cellules qui doivent être liées à la séquence, utilisez l'identifiant "cellWithSegue", pour le reste, "cellWithoutSegue".

Cette méthode semble beaucoup plus facile à mettre en œuvre et ne modifie pas non plus la façon dont les séquences sont censées fonctionner.

18
zirinisp

Je peux me tromper ici, mais après m'être débattu avec cela, je viens de désactiver l'interaction utilisateur de la cellule sur les cellules où je ne voulais pas que la seque soit déclenchée (dans cellForRowAtIndexPath :). Semble fonctionner parfaitement, et ce n'est que 1 ligne de code!

cell.userInteractionEnabled = NO;
14
SomaMan

La solution la plus simple consiste à créer une séquence manuelle dans le story-board et à l'utiliser comme indiqué ci-dessous.

[self performSegueWithIdentifier:@"loginSuccessSegue" sender:self];

Ou


@Fabio: J'essayais d'obtenir une solution pour le même type de cas d'utilisation et j'ai presque trouvé une solution.

Cas d'utilisation 1. Arrêter la transition de transition conditionnellement 2. Changer la vue de destinationContrôleur conditionnellement

Solution:

Utilisez un enchaînement "personnalisé". Suivez les étapes ci-dessous pour créer une séquence personnalisée 1. Créez une sous-classe de UIStoryboardSegue "MyCustomSegue.h"

@interface MyCustomSegue : UIStoryboardSegue
@end

"MyCustomSegue.m"

Remplacez initWithIdentifier pour implémenter les cas d'utilisation 1 et 2 Si vous retournez nil, la séquence sera annulée/aucune action ne sera entreprise Vous instanciez votre ViewController et le définissez comme destination. Vous pouvez également définir la destination comme votre ancien fichier xib .. ce code est commenté, mais je me suis assuré que cela fonctionnerait.

@implementation MyCustomSegue
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination{

    UIStoryboard *storyBoard= [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];

    UIViewController *viewController = [storyBoard instantiateViewControllerWithIdentifier:@"testIdentifier"];

    // MyViewController* viewController= [[MyViewController alloc]initWithNibName:@"MyViewController" bundle:nil];
    return [super initWithIdentifier:identifier source:source destination:viewController];
}
  1. Vous devez remplacer "performer".

Vous pouvez également implémenter le cas d'utilisation 1 ici.

- (void)perform {
    // if either source or destination is nil, stop
    if (nil == self.sourceViewController || nil == self.destinationViewController) return;
    // return; //No Action. Segue will be cancelled
    UINavigationController *ctrl = [self.sourceViewController navigationController];
    [ctrl
     pushViewController:self.destinationViewController
     animated:YES];
}

J'espère que cela t'aides. Veuillez écrire si vous n'êtes pas clair.

11
Johnson Mathew

Une façon agréable et légère de le faire est à l'intérieur de la méthode UITableViewDelegate tableView:willSelectRowAtIndexPath:— le cas échéant. YMMV.

Voici comment je le fais (iOS 5, ARC). J'utilise une variable d'instance BOOL dans mon contrôleur de vue, initialement définie sur False dans viewDidLoad. Le contrôleur de vue de destination auquel les cellules du tableau sont configurées pour se connecter à dans Interface Builder repose sur un peu de données ayant été chargées à partir d'un serveur, donc je ne veux pas que la transition se produise tant que je n'ai pas les données.

Simplifié, voici à quoi ça ressemble:

@implementation SomeViewController {
    BOOL okayToSegue;
}

...

- (void)viewDidLoad
{
    [super viewDidLoad];
    okayToSegue = NO;
    // The success block for the data retrieval
    void(^successBlock)(void) = ^{
        // Other code...
        okayToSegue = YES;
    }
    [[ServerClient sharedClient] getDataFromServerSuccess:successBlock];
}

...

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!okayToSegue) {
        return nil;
    }
    return indexPath;
}

Ignorer des détails comme ce bit sharedClient là-bas, c'est juste la façon dont j'appelle ma sous-classe AFHTTPClient avec le bloc de réussite, dans la vraie vie, j'aurais un bloc d'échec et d'autres choses aussi.

Renvoyer nil dans tableView:willSelectRowAtIndexPath: fait taper sur une cellule du tableau pour ne rien faire. Ce n'est qu'après avoir obtenu Word de mon instance AFHTTPClient (via successBlock) que les données dont le contrôleur à afficher se prépare sont prêtes et en attente, je change la variable d'instance et les futurs taps fonctionneront très bien. Dans le code réel, vous voudrez avoir une notification visible par l'utilisateur ou un signe révélateur visuellement évident que la transition n'est pas encore possible.

Donc, quelle que soit la logique dont vous avez besoin pour déterminer si la transition à partir d'une cellule de tableau est correcte ou non, dans de nombreux cas, il est possible de le faire de cette manière.

4
JK Laiho

La façon dont le modèle d'Apple le fait pour l'iPad popOver consiste à utiliser un enchaînement manuel, par opposition à un enchaînement automatique qui déclenche sur une touche, le manuel doit être déclenché avec performSegueWithIdentifier:

Pour créer un enchaînement manuel au lieu de faire un ctrl-glisser depuis l'élément auquel vous pensez ctrl-glisser depuis l'icône du contrôleur de la vue, définissez un identifiant pour le segue et vous avez terminé dans IB.

manual segues

2
valexa

Voici une autre solution que je viens de trouver.

Dans votre Mainstoryboard TableView, lorsque vous utilisez la transition automatique de votre cellule (identifiant = Cell) vers la vue de destination, vous pouvez également ajouter une autre cellule avec un autre identifiant (identifiant = CellWithoutSegue). Ainsi, lorsque vous créez une nouvelle cellule dans cellForRowAtIndexPath, réutilisez simplement l'identifiant de cellule que vous souhaitez (avec ou sans séquence).

J'espère que cela aide!

(Dites-moi si vous voulez des exemples de code source).

Cordialement,

0
Dorine M