Tratando de manejar la acción del botón de navegación "atrás" en iOS


Necesito detectar cuando el usuario toca el botón "atrás" en la barra de navegación, con el fin de realizar algunas operaciones cuando eso ocurre. Estoy tratando de establecer manualmente una acción en dicho botón, de esta manera:

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

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

   [self.navigationController popViewControllerAnimated:NO];
}

Primero coloqué ese código en el controlador de vista en sí, pero descubrí que self.navigationItem.backBarButtonItem parecía ser nil, así que moví ese mismo código al controlador de vista padre, que empuja el primero a la pila de navegación. Pero tampoco puedo hacer que funcione. He leído algunos posts sobre este problema, y algunos de ellos dijeron que el selector debe configurarse en el controlador de vista padre, pero para mí no funciona de todos modos... ¿Qué podría estar haciendo mal?

Gracias

Author: AppsDev, 2013-09-16

7 answers

Pruebe este código usando el método VIewWillDisappear para detectar la pulsación del botón atrás 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];
}

O hay otra forma de obtener la Acción del botón de navegación Atrás.

Crear botón personalizado para UINavigationItem del botón atrás .

Para Ex:

En 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];
}

Swift :

override func willMoveToParentViewController(parent: UIViewController?) 
{
    if parent == nil 
    {
        // Back btn Event handler
    }
}
 125
Author: Kumar KL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-02 07:51:02

Swift

override func didMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        //"Back pressed"
    }
}
 38
Author: dadachi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-14 16:41:53

Tal vez esta respuesta no se ajuste a su explicación, sino al título de la pregunta. Es útil cuando estás tratando de saber cuándo tocaste el botón atrás en un UINavigationBar.

En este caso puede usar el protocolo UINavigationBarDelegate e implementar uno de estos métodos:

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

Cuando se llama al método didPopItem, es porque pulsaste el botón atrás o usaste el método [UINavigationBar popNavigationItemAnimated:] y la barra de navegación hizo estallar el elemento.

Ahora, si desea saber qué acción desencadenó el método didPopItem puede usar bandera.

Con este enfoque, no necesito agregar manualmente un elemento del botón de la barra izquierda con una imagen de flecha para que sea similar al botón atrás de iOS, y poder establecer mi objetivo/acción personalizada.


Veamos un ejemplo:

Tengo un controlador de vista que tiene un controlador de vista de página y una vista de indicador de página personalizada. Estoy usando una costumbre UINavigationBar para mostrar un título para saber en qué página soy yo y el botón atrás para regresar a la página anterior. Y yo también puede deslizar a la página anterior/siguiente en page controller.

#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];
        }
    }

}

Entonces implemento los métodos delegados de 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;
}

En este caso usé shouldPopItem porque el pop está animado y quería manejar el botón atrás inmediatamente y no esperar hasta que la transición haya terminado.

 14
Author: Firula,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-30 16:32:41

El problema con didMoveToParentViewController es que se llama una vez que la vista padre es completamente visible de nuevo, por lo que si necesita realizar algunas tareas antes de eso, no funcionará.

Y no funciona con el gesto de animación impulsado. Usar willMoveToParentViewController funciona mejor.

Objective-c

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

Swift

override func willMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        // ...  
    }
}
 12
Author: Nico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 10:51:56

Esta es la versión Objective-C de la respuesta de dadachi :

Objetivo-C

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        NSLog(@"Back Pressed");
    }
}
 6
Author: Ashish Kakkad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:52

Establece el delegado de la UINavigationBar, y luego usa:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    //handle the action here
}
 3
Author: Jeffrey Sun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 06:28:37

Establecer el UINavigationController Delegate e implementar este func delegado (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
Author: mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-26 15:23:34