web-dev-qa-db-fra.com

Essayer de gérer l'action du bouton de navigation "retour" dans iOS

Je dois détecter le moment où l'utilisateur appuie sur le bouton "Précédent" de la barre de navigation, afin d'effectuer certaines opérations lorsque cela se produit. J'essaie de définir manuellement une action sur un tel bouton, de cette façon:

[self.navigationItem.backBarButtonItem setAction:@selector(performBackNavigation:)];

- (void)performBackNavigation:(id)sender
{
   // Do operations

   [self.navigationController popViewControllerAnimated:NO];
}

J'ai d'abord placé ce code dans le contrôleur de vue lui-même, mais j'ai constaté que self.navigationItem.backBarButtonItem semblait être nil et j'ai donc déplacé ce même code vers le contrôleur de vue parent, ce qui place l'ancien dans la pile de navigation. Mais je ne suis pas capable de le faire fonctionner. J'ai lu des articles sur ce problème, et certains d'entre eux ont dit que le sélecteur doit être défini sur le contrôleur de vue parent, mais pour moi, cela ne fonctionne pas de toute façon ... Qu'est-ce que je peux faire de mal?

Merci

67
AppsDev

Essayez ce code en utilisant la méthode VIewWillDisappear pour détecter la pression du bouton retour de NavigationItem:

-(void) viewWillDisappear:(BOOL)animated
{
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) 
    {
        // Navigation button was pressed. Do some stuff 
        [self.navigationController popViewControllerAnimated:NO];
    }
    [super viewWillDisappear:animated];
}

OU Il existe un autre moyen d’obtenir l’action du bouton Navigation BAck.

Créer un bouton personnalisé pour UINavigationItem of back button.

Pour Ex: 

Dans ViewDidLoad:

- (void)viewDidLoad 
{
    [super viewDidLoad];
    UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:self action:@selector(home:)];
    self.navigationItem.leftBarButtonItem=newBackButton;
}

-(void)home:(UIBarButtonItem *)sender 
{
    [self.navigationController popToRootViewControllerAnimated:YES];
}

Rapide :

override func willMoveToParentViewController(parent: UIViewController?) 
{
    if parent == nil 
    {
        // Back btn Event handler
    }
}
126
Kumar KL

Rapide

override func didMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        //"Back pressed"
    }
}
40
dadachi

Peut-être que cette réponse ne correspond pas à votre explication, mais au titre de la question. C'est utile lorsque vous essayez de savoir quand vous avez tapé sur le bouton Précédent d'une UINavigationBar.

Dans ce cas, vous pouvez utiliser le protocole UINavigationBarDelegate et implémenter l'une des méthodes suivantes:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;

Lorsque la méthode didPopItem est appelée, c'est que vous avez appuyé sur le bouton Précédent ou sur la méthode [UINavigationBar popNavigationItemAnimated:] et que la barre de navigation a fait apparaître l'élément.

Maintenant, si vous voulez savoir quelle action a déclenché la méthode didPopItem, vous pouvez utiliser un indicateur.

Avec cette approche, je n'ai pas besoin d'ajouter manuellement un élément du bouton de barre gauche avec une image en forme de flèche pour le rendre similaire au bouton de retour iOS et pour pouvoir définir ma cible/action personnalisée.


Voyons un exemple:

J'ai un contrôleur de vue qui a un contrôleur de vue de page et une vue d'indicateur de page personnalisée. J'utilise également un UINavigationBar personnalisé pour afficher un titre et savoir sur quelle page je suis et sur le bouton Précédent pour revenir à la page précédente. Et je peux aussi glisser à la page précédente/suivante sur le contrôleur de page.

#pragma mark - UIPageViewController Delegate Methods
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if( completed ) {

        //...

        if( currentIndex > lastIndex ) {

            UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Some page title"];

            [[_someViewController navigationBar] pushNavigationItem:navigationItem animated:YES];
            [[_someViewController pageControl] setCurrentPage:currentIndex];
        } else {
            _autoPop = YES; //We pop the item automatically from code.
            [[_someViewController navigationBar] popNavigationItemAnimated:YES];
            [[_someViewController pageControl] setCurrentPage:currentIndex];
        }
    }

}

Alors j'implémente les méthodes de délégation UINavigationBar:

#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    if( !_autoPop ) {
        //Pop by back button tap
    } else {
        //Pop from code
    }

    _autoPop = NO;

    return YES;
}

Dans ce cas, j'ai utilisé shouldPopItem car la pop est animée et je voulais gérer le bouton de retour immédiatement et ne pas attendre la fin de la transition.

16
Firula

Le problème avec didMoveToParentViewController est qu’elle est appelée une fois que la vue parent est à nouveau complètement visible. Par conséquent, si vous devez effectuer certaines tâches auparavant, cela ne fonctionnera pas.

Et cela ne fonctionne pas avec le geste d'animation piloté . Utiliser willMoveToParentViewController fonctionne mieux.

Objectif c

- (void)willMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        // ...
    }
}

Rapide

override func willMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        // ...  
    }
}
12
Nico

Ceci est la version Objective-C de dadachi's Answer:

Objectif c

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        NSLog(@"Back Pressed");
    }
}
6
Ashish Kakkad

Définissez le délégué de UINavigationBar, puis utilisez:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    //handle the action here
}
2
Jeffrey Sun

Aucune des autres solutions ne fonctionnait pour moi, mais cela fonctionne:

Créez votre propre sous-classe de UINavigationController, faites en sorte qu'elle implémente UINavigationBarDelegate (inutile de définir manuellement le délégué de la barre de navigation), ajoutez une extension UIViewController qui définit une méthode à appeler lors d'une pression sur le bouton Précédent, puis implémentez cette méthode dans votre sous-classe UINavigationController :

func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
    self.topViewController?.methodToBeCalledOnBackButtonPress()
    self.popViewController(animated: true)
    return true
}
1
Shady

Définissez le UINavigationControllerDelegate et implémentez cette fonction de délégué (Swift):

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    if viewController is <target class> {
        //if the only way to get back - back button was pressed
    }
}
1
mark

Utilisez une sous-classe UINavigationController personnalisée, qui implémente la méthode shouldPop

En rapide:

class NavigationController: UINavigationController, UINavigationBarDelegate
{
    var shouldPopHandler: (() -> Bool)?

    func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool
    {
        if let shouldPopHandler = self.shouldPopHandler, !shouldPopHandler()
        {
            return false
        }
        self.popViewController(animated: true) // Needed!
        return true
    }
}

Lorsque cette option est définie, votre shouldPopHandler() sera appelé pour décider si le contrôleur sera activé ou non. Quand ce n'est pas réglé, il va juste être sauté comme d'habitude.

C'est une bonne idée de désactiver UINavigationControllers interactivePopGestureRecognizer car le geste n'appellera pas votre gestionnaire.

0
Rivera

Dans Swift 4 ou plus:

override func didMove(toParent parent: UIViewController?) {
    if parent == nil {
        //"Back pressed"
    }
}
0
iMichele