Estoy intentando sobreescribir la acción predeterminada del botón atrás en un controlador de navegación. Me ha proporcionado un objetivo de una acción en el botón personalizado. La cosa rara es que cuando la asignación de la misma a pesar de que el boton atrás atributo de no prestar atención a ellos y sólo aparece la vista actual y regresa a la raíz:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                  initWithTitle: @"Servers" 
                                  style:UIBarButtonItemStylePlain 
                                  target:self 
                                  action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;

Tan pronto como me puse a través de la leftBarButtonItem en el navigationItem llama mi acción, sin embargo, a continuación, el botón se ve como una llanura de la ronda uno, en lugar de la flecha de la espalda de uno:

self.navigationItem.leftBarButtonItem = backButton;

¿Cómo la puedo llamar a mi costumbre de acción antes de volver a la raíz de la vista? Hay una manera para sobrescribir el valor predeterminado de la acción, o es que hay un método que es llamado siempre al salir de una vista (viewDidUnload no hace eso)?

action:@selector(inicio)]; necesita un : después de que el selector de action:@selector(la casa:)]; de lo contrario no funcionará
Eso no es cierto a menos que el método es declarado con el colon. Es perfectamente válido para los botones de llamada selectores de que no toma ningún parámetro.
posibles duplicados de Detener el auto.navigationItem.leftBarButtonItem de salir de una vista
¿Por qué no Apple proporcionar un botón con el estilo de la forma de un botón atrás? Parece bastante obvio.
Buscar en la la solución en este hilo

OriginalEl autor Parrots | 2009-07-31

28 Comentarios

  1. 363

    Prueba a poner esto en el controlador de vista de donde se quiere detectar la prensa:

    -(void) viewWillDisappear:(BOOL)animated {
        if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
           //back button was pressed.  We know this is true because self is no longer
           //in the navigation stack.  
        }
        [super viewWillDisappear:animated];
    }
    Gracias – intuitivo, sencillo y de trabajo!
    +1 gran hack, pero no ofrecen la posibilidad de controlar la animación de pop
    No me funciona si me envían un mensaje al delegado, a través de un botón y el delegado de la cop el controlador – todavía incendios.
    Otro problema es que no se puede diferenciar si el usuario pulsa el botón atrás o si a través de programación llamado [auto.navigationController popViewControllerAnimated:SÍ]
    Sólo un FYI: Swift versión: if (find(self.navigationController!.viewControllers as! [UIViewController],self)==nil)

    OriginalEl autor William Jockusch

  2. 171

    He implementado UIViewController-BackButtonHandler extensión. No necesita subclase nada, sólo tienes que poner en tu proyecto y reemplazar navigationShouldPopOnBackButton método en UIViewController clase:

    -(BOOL) navigationShouldPopOnBackButton {
        if(needsShowConfirmation) {
            //Show confirmation alert
            //...
            return NO; //Ignore 'Back' button this time
        }
        return YES; //Process 'Back' button click and Pop view controler
    }

    Ejemplo de descarga de la aplicación.

    Esta es la solución más limpia que he visto, la mejor y más sencilla de utilizar sus propios UIButton. Gracias!
    El navigationBar:shouldPopItem: no es un método privado, ya que es una parte de UINavigationBarDelegate protocolo.
    esto debe ser aceptado respuesta!
    Acabo de implementado este (genial por CIERTO) en iOS 7.1 y notó que después de regresar NO el botón atrás permanece en estado deshabilitado (visualmente, porque todavía recibe y reacciona a los eventos de toque). He trabajado alrededor de ella mediante la adición de un else declaración a la shouldPop de verificación y ciclismo a través de la barra de navegación de subvistas, y el establecimiento de la alpha valor de 1 si es necesario dentro de una animación bloque: gist.github.com/idevsoftware/9754057
    Este es uno de los mejores que he visto nunca. Muchas gracias.

    OriginalEl autor onegray

  3. 42

    A diferencia de Amagrammer dijo, es posible. Usted tiene subclase su navigationController. Me explicó todo lo que aquí (incluyendo el código de ejemplo): http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller

    Hola Juan, gracias por compartir. Buen resultado.
    La documentación de Apple (developer.apple.com/iphone/library/documentation/UIKit/…), dice que «Esta clase no es la intención para la creación de subclases». Aunque no estoy seguro de lo que quieren decir con esto – que podría significar «no debería normalmente se necesita para hacer eso», o se podría decir «vamos a rechazar su aplicación, si te equivocas con nuestro controlador»…
    Se puede prevenir una vista a partir de la salida de usar este método? ¿Qué haría usted en el popViewControllerAnimated método de regreso si desea que la vista no salir?
    Sí, se puede. Simplemente no llamar al método de la superclase en su aplicación, tenga en cuenta! Usted no debe hacer eso, el usuario espera que ir de nuevo en la navegación. Lo que puedes hacer es pedir una confirmación. De acuerdo a las Manzanas documentación popViewController devuelve: «El controlador de vista de que había aparecido de la pila.» Así que cuando nada se apareció su debe devolver nil;
    Creo que tu respuesta acerca de la prevención de una vista a partir de la salida puede ser algo incorrecto. Si puedo mostrar un «confirmar» mensaje de las subclases de la implementación de popViewControllerAnimated:, el NavigationBar todavía se anima a subir un nivel en el árbol independientemente de lo que yo regrese. Esto parece ser debido a que al hacer clic en el botón atrás llamadas shouldPopNavigationItem en la barra de navegación. Me voy a volver nil de mi subclases método como recommendd.

    OriginalEl autor HansPinckaers

  4. 13

    Swift Versión:

    (de https://stackoverflow.com/a/19132881/826435)

    En su controlador de vista de que acaba de cumplir un protocolo y realizar cualquier acción que usted necesita:

    extension MyViewController: NavigationControllerBackButtonDelegate {
        func shouldPopOnBackButtonPress() -> Bool {
            performSomeActionOnThePressOfABackButton()
            return false
        }
    }

    A continuación, crear una clase, digamos que NavigationController+BackButton, y solo copie-pegue el código de abajo:

    protocol NavigationControllerBackButtonDelegate {
        func shouldPopOnBackButtonPress() -> Bool
    }
    
    extension UINavigationController {
        public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
            //Prevents from a synchronization issue of popping too many navigation items
            //and not enough view controllers or viceversa from unusual tapping
            if viewControllers.count < navigationBar.items!.count {
                return true
            }
    
            //Check if we have a view controller that wants to respond to being popped
            var shouldPop = true
            if let viewController = topViewController as? NavigationControllerBackButtonDelegate {
                shouldPop = viewController.shouldPopOnBackButtonPress()
            }
    
            if (shouldPop) {
                DispatchQueue.main.async {
                    self.popViewController(animated: true)
                }
            } else {
                //Prevent the back button from staying in an disabled state
                for view in navigationBar.subviews {
                    if view.alpha < 1.0 {
                        UIView.animate(withDuration: 0.25, animations: {
                            view.alpha = 1.0
                        })
                    }
                }
    
            }
    
            return false
        }
    }
    Tal vez me he perdido algo, pero no trabajo para mí, el método performSomeActionOnThePressOfABackbutton de la extensión nunca se llama
    tal vez un malentendido? shouldPopOnBackButtonPress deben recibir llamadas mientras que no hay errores. performSomeActionOnThePressOfABackButton es simplemente un método que no existe.
    Yo lo entendía, por eso he creado un método performSomeActionOnThePressOfABackButton en mi controlador para ejecutar una acción específica cuando se pulsa el botón atrás, pero este método nunca fue llamado, la acción es una parte normal de devolución
    No funciona para mí ninguno de los dos. El shouldPop método nunca es llamado. ¿Establecer un delegado en algún lugar?
    Acabo de probar este nuevo y parece que algo ha cambiado. Pieza clave para entender que en una UINavigationController, el navigationBar.delegate se establece en el controlador de navegación. Así que los métodos DEBEN recibir llamadas. Sin embargo, en Swift, yo no puedo ser llamado, incluso en una subclase. Yo, sin embargo, llegar a ser llamado en Objective-C, así que sólo uso el Objetivo-C versión por ahora. Podría ser un Swift error.

    OriginalEl autor kgaidis

  5. 5

    No es posible hacerlo directamente. Hay un par de alternativas:

    1. Crear su propio personalizado UIBarButtonItem que valida el toque y pops si pasa la prueba
    2. Validar el contenido del campo de formulario utilizando un UITextField método de delegado, tales como -textFieldShouldReturn:, que se llama después de que el Return o Done botón es presionado en el teclado

    La desventaja de la primera opción es la que apunta a la izquierda-flecha estilo del botón atrás no se puede acceder desde una costumbre botón de la barra. Así que hay que utilizar una imagen o ir con un estilo regular botón.

    La segunda opción es agradable porque tienes el campo de texto de vuelta en el método de delegado, para que pueda dirigirse a su lógica de validación para el específico campo de texto enviado al delegado de devolución de llamada de método.

    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor Alex Reynolds

  6. 5

    Para algunos roscado razones, la solución es mencionado por @HansPinckaers no era para mí, pero me encontré con un muy más fácil manera de atrapar a un toque en el botón atrás, y quiero pin esta de aquí abajo en caso de que esto podría evitar las horas de engaños para alguien más.
    El truco es muy fácil : sólo hay que añadir un transparente UIButton como una subvista a su UINavigationBar, y establecer su selectores para él como si fuese el botón real!
    He aquí un ejemplo de uso de Monotouch y C#, pero la traducción a objective-c no debería ser demasiado difícil de encontrar.

    public class Test : UIViewController {
        public override void ViewDidLoad() {
            UIButton b = new UIButton(new RectangleF(0, 0, 60, 44)); //width must be adapted to label contained in button
            b.BackgroundColor = UIColor.Clear; //making the background invisible
            b.Title = string.Empty; //and no need to write anything
            b.TouchDown += delegate {
                Console.WriteLine("caught!");
                if (true) //check what you want here
                    NavigationController.PopViewControllerAnimated(true); //and then we pop if we want
            };
            NavigationController.NavigationBar.AddSubview(button); //insert the button to the nav bar
        }
    }

    Hecho de la diversión : para propósitos de prueba y encontrar buenas dimensiones para mi falso botón, me puse su color de fondo azul… Y se muestra detrás de el botón atrás! De todos modos, todavía capturas cualquier toque trabajar el botón original.

    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor psycho

  7. 3

    Esta técnica le permite cambiar el texto del botón «atrás» sin afectar el título de cualquiera de la vista de los controladores o ver la parte de atrás del botón de cambio de texto durante la animación.

    Agregar esto al método init en el llamar vista controlador:

    UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];   
    temporaryBarButtonItem.title = @"Back";
    self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
    [temporaryBarButtonItem release];

    OriginalEl autor Jason Moore

  8. 3

    Manera más fácil

    Puede utilizar el UINavigationController el delegado de métodos. El método willShowViewController se llama cuando el botón atrás de su VC es presionado.hacer lo que quieras cuando btn presionado

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
    Asegúrese de que su controlador de vista se fija a sí mismo como el delegado de la heredada navigationController y se ajusta a la UINavigationControllerDelegate protocolo

    OriginalEl autor Xar E Ahmer

  9. 3

    Encontrado una solución que conserva el botón atrás el estilo.
    Agregue el método siguiente a su controlador de vista.

    -(void) overrideBack{
    
        UIButton *transparentButton = [[UIButton alloc] init];
        [transparentButton setFrame:CGRectMake(0,0, 50, 40)];
        [transparentButton setBackgroundColor:[UIColor clearColor]];
        [transparentButton addTarget:self action:@selector(backAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.navigationController.navigationBar addSubview:transparentButton];
    
    
    }

    Ahora proporcionan una funcionalidad que necesita en el siguiente método:

    -(void)backAction:(UIBarButtonItem *)sender {
        //Your functionality
    }

    Todo lo que hace es cubrir el botón atrás con un botón transparente 😉

    OriginalEl autor Sarasranglt

  10. 2

    Yo no creo que esto sea posible, fácilmente. La única manera que yo creo que para evitar esto es hacer su propio botón de flecha de la imagen al lugar. Fue frustrante para mí al principio, pero ya veo por qué, para mantener la coherencia del bien, se quedó afuera.

    Usted puede conseguir cerca (sin flecha) mediante la creación de un regular botón y ocultar el defecto botón atrás:

    self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Servers" style:UIBarButtonItemStyleDone target:nil action:nil] autorelease];
    self.navigationItem.hidesBackButton = YES;
    Sí, el problema es que quiero que se vea igual que la normal botón atrás, sólo tiene que llamar a mi costumbre de acción en primera…

    OriginalEl autor Meltemi

  11. 2

    Hay una manera más fácil con sólo crear subclases de la método delegado de la UINavigationBar y reemplazar la ShouldPopItemmétodo.

    Creo que te refieres a decir subclase de la UINavigationController clase e implementar un shouldPopItem método. Que está funcionando bien para mí. Sin embargo, ese método no debe volver simplemente SÍ o NO, como sería de esperar. Una explicación de la solución y está disponible aquí: stackoverflow.com/a/7453933/462162

    OriginalEl autor jazzyjef2002

  12. 2

    Aquí está mi solución rápida. En la subclase de UIViewController, reemplazar el navigationShouldPopOnBackButton método.

    extension UIViewController {
        func navigationShouldPopOnBackButton() -> Bool {
            return true
        }
    }
    
    extension UINavigationController {
    
        func navigationBar(navigationBar: UINavigationBar, shouldPopItem item: UINavigationItem) -> Bool {
            if let vc = self.topViewController {
                if vc.navigationShouldPopOnBackButton() {
                    self.popViewControllerAnimated(true)
                } else {
                    for it in navigationBar.subviews {
                        let view = it as! UIView
                        if view.alpha < 1.0 {
                            [UIView .animateWithDuration(0.25, animations: { () -> Void in
                                view.alpha = 1.0
                            })]
                        }
                    }
                    return false
                }
            }
            return true
        }
    
    }
    Método de reemplazo navigationShouldPopOnBackButton en UIViewController no funciona – Programa se ejecuta método padre no la reemplaza. Alguna solución para eso? ¿Alguien tiene el mismo problema?
    se va todo el camino de regreso a rootview si devolver true
    He aquí una solución escribí que parece que funciona para mí: stackoverflow.com/a/34343418/826435

    OriginalEl autor AutomatonTec

  13. 2

    onegray la solución no es seguro.De acuerdo a los documentos oficiales por parte de Apple,https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html,
    debemos evitar hacer eso.

    «Si el nombre de un método declarado en una categoría es el mismo que el de un método en la clase original, o un método en otra categoría en la misma clase (o incluso un superclase), el comportamiento es indefinido como para que la implementación del método se utiliza en tiempo de ejecución. Esto es menos probable que sea un problema si usted está utilizando categorías con sus propias clases, pero puede causar problemas cuando se utiliza categorías para agregar métodos estándar de Cacao o Cocoa Touch clases.»

    OriginalEl autor user2612791

  14. 2

    Uso De Swift:

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        if self.navigationController?.topViewController != self {
            print("back button tapped")
        }
    }
    Como de iOS 10, y quizás antes, esto ya no funciona.

    OriginalEl autor Murray Sagal

  15. 2

    Aquí es Swift 3 versión de @oneway‘s respuesta para la captura de la barra de navegación botón atrás del evento antes de que se despiden. Como UINavigationBarDelegate no puede ser utilizado para UIViewController, usted necesita para crear un delegado, que se activan cuando navigationBar shouldPop se llama.

    @objc public protocol BackButtonDelegate {
          @objc optional func navigationShouldPopOnBackButton() -> Bool 
    }
    
    extension UINavigationController: UINavigationBarDelegate  {
    
        public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
    
            if viewControllers.count < (navigationBar.items?.count)! {                
                return true
            }
    
            var shouldPop = true
            let vc = self.topViewController
    
            if vc.responds(to: #selector(vc.navigationShouldPopOnBackButton)) {
                shouldPop = vc.navigationShouldPopOnBackButton()
            }
    
            if shouldPop {
                DispatchQueue.main.async {
                    self.popViewController(animated: true)
                }
            } else {
                for subView in navigationBar.subviews {
                    if(0 < subView.alpha && subView.alpha < 1) {
                        UIView.animate(withDuration: 0.25, animations: {
                            subView.alpha = 1
                        })
                    }
                }
            }
    
            return false
        }
    }

    Y, a continuación, en la vista controlador agregar el delegado de la función:

    class BaseVC: UIViewController, BackButtonDelegate {
        func navigationShouldPopOnBackButton() -> Bool {
            if ... {
                return true
            } else {
                return false
            }        
        }
    }

    Me he dado cuenta de que con frecuencia se desea agregar una alerta de controlador para que los usuarios decidan si quieren volver. Si es así, usted siempre puede return false en navigationShouldPopOnBackButton() función y cerca de su punto de vista controlador por hacer algo como esto:

    func navigationShouldPopOnBackButton() -> Bool {
         let alert = UIAlertController(title: "Warning",
                                              message: "Do you want to quit?",
                                              preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { UIAlertAction in self.yes()}))
                alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { UIAlertAction in self.no()}))
                present(alert, animated: true, completion: nil)
          return false
    }
    
    func yes() {
         print("yes")
         DispatchQueue.main.async {
                _ = self.navigationController?.popViewController(animated: true)
            }
    }
    
    func no() {
        print("no")       
    }
    Estoy recibiendo un error: Value of type 'UIViewController' has no member 'navigationShouldPopOnBackButton' cuando intento compilar el código, para la línea if vc.responds(to: #selector(v... También, la self.topViewController devuelve un opcional y no es una advertencia para que también.
    Por lo que vale, me he fijado que el código haciendo: let vc = self.topViewController as! MyViewController y parece funcionar bien hasta ahora. Si usted cree que es un derecho de cambiar, se podría modificar el código. También, si usted siente que no se debe hacer, voy a estar contento de saber por qué. Gracias por este código. Probablemente, usted debe escribir un blog acerca de esto, ya que esta respuesta es enterrado como por los votos.
    La razón por la que consiguió que el error es su MyViewController pueden no ajustarse a BackButtonDelegate. En lugar de forzar a desenvolver, usted debe hacer guard let vc = self.topViewController as? MyViewController else { return true } para evitar un posible accidente.
    Gracias. Creo que la guardia de la declaración debe ser: guard let vc = self.topViewController as? MyViewController else { self.popViewController(animated: true) return true } para asegurarse de que la pantalla se mueve a la derecha de la página en caso de que no se puede con razón emitidos. Ahora entiendo que el navigationBar se llama a la función en todos los VCs y no sólo el viewcontroller donde este código existente. Puede ser que va a ser bueno para actualizar el código en tu respuesta ? Gracias.

    OriginalEl autor Lawliet

  16. 1

    Mediante el destino y la acción de las variables que actualmente se está dejando ‘nil’, usted debería ser capaz de alambre el guardar cuadros de diálogo en la que se llama cuando el botón es «seleccionado». Cuidado, esto puede activar extraños momentos.

    Estoy de acuerdo en todo con Amagrammer, pero creo que no sería difícil hacer que el botón con la flecha personalizado. Acabo de cambiar el nombre del botón atrás, tomar una captura de pantalla, photoshop el tamaño de los botones necesarios, y tiene que ser la imagen en la parte superior de tu botón.

    Estoy de acuerdo en que podría photoshop y creo que yo podría hacer esto si yo realmente quería hacerlo, pero ahora han decidido cambiar el aspecto un poco para conseguir que esto funcione de la manera que desee.
    Sí, excepto que las acciones no se activa cuando se unen a la backBarButtonItem. No sé si esto es un bug o una función; es posible que incluso Apple no sabe. Como para el photoshopping ejercicio, de nuevo, me gustaría ser cautelosos de que Apple iba a rechazar la aplicación para la aplicación indebida de una canónica símbolo.
    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor TahoeWolverine

  17. 1

    Usted puede tratar de acceder a la NavigationBars el Botón de la Derecha del elemento y establezca su propiedad de selector de…heres una referencia UIBarButtonItem referencia, otra cosa si esta doenst trabajo que se def trabajo es, establecer el derecho de elemento de botón de la barra de navegación personalizado para un UIBarButtonItem que usted cree y establezca el selector…espero que esto ayude

    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor Daniel

  18. 1

    Para un formulario que requiere la intervención del usuario esta, me gustaría recomendar invocando como un «modal» en lugar de la parte de la pila de navegación. De esa manera tienen que cuidar de los negocios en el formulario a continuación, usted puede validar y cerrarlo mediante un botón personalizado. Usted puede incluso diseñar una barra de navegación que tiene el mismo aspecto que el resto de su aplicación, pero le da más control.

    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor Travis M.

  19. 1

    Al menos en Xcode 5, no es un simple y bastante bueno (no perfecta) de la solución. En IB, arrastre un Botón de la Barra de Punto fuera de las Utilidades del panel y colóquelo en el lado izquierdo de la Barra de Navegación en la parte Posterior botón. Establecer la etiqueta de «Atrás». Usted tendrá un funcionamiento botón que usted puede atar a su IBAction y cerca de su viewController. Estoy haciendo un trabajo y, a continuación, el desencadenamiento de un relajarte segue y funciona perfectamente.

    Lo que no es lo ideal es que este botón no obtener la < flecha y no llevar adelante la anterior VCs título, pero creo que esto puede ser administrado. Para mis propósitos, me puse el nuevo botón Atrás para ser un «Hecho» botón, de forma que su propósito es claro.

    También terminará con dos botones de la Espalda en el IB navegador, pero es bastante fácil de etiqueta para la claridad.

    Configuración de acción para el botón atrás en la navegación controlador

    OriginalEl autor Dan Loughney

  20. 1

    Swift

    override func viewWillDisappear(animated: Bool) {
        let viewControllers = self.navigationController?.viewControllers!
        if indexOfArray(viewControllers!, searchObject: self) == nil {
            //do something
        }
        super.viewWillDisappear(animated)
    }
    
    func indexOfArray(array:[AnyObject], searchObject: AnyObject)-> Int? {
        for (index, value) in enumerate(array) {
            if value as UIViewController == searchObject as UIViewController {
                return index
            }
        }
        return nil
    }

    OriginalEl autor zono

  21. 1

    Este enfoque funcionó para mí (pero el botón de «Atrás» no tendrá el «<» signo):

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        UIBarButtonItem* backNavButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
                                                                          style:UIBarButtonItemStyleBordered
                                                                         target:self
                                                                         action:@selector(backButtonClicked)];
        self.navigationItem.leftBarButtonItem = backNavButton;
    }
    
    -(void)backButtonClicked
    {
        //Do something...
        AppDelegate* delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
        [delegate.navController popViewControllerAnimated:YES];
    }

    OriginalEl autor Ivan

  22. 1

    La respuesta de @William es correcto sin embargo, si el usuario inicia un golpe-a-go-back gesto de la viewWillDisappear se llama al método e incluso del «yo», no estará en la pila de navegación (es decir, yo.navigationController.viewControllers no contiene ‘auto’), incluso si el pase no está terminado y el controlador de vista es, en realidad, no apareció. Por lo tanto, la solución sería:

    1. Deshabilitar el golpe-a-go-back gesto en viewDidAppear y sólo permite utilizar el botón atrás, mediante el uso de:

      if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
      {
          self.navigationController.interactivePopGestureRecognizer.enabled = NO;
      }
    2. O simplemente utilizar viewDidDisappear lugar, de la siguiente manera:

      - (void)viewDidDisappear:(BOOL)animated
      {
          [super viewDidDisappear:animated];
          if (![self.navigationController.viewControllers containsObject:self])
          {
              //back button was pressed or the the swipe-to-go-back gesture was
              //completed. We know this is true because self is no longer
              //in the navigation stack.
          }
      }

    OriginalEl autor boherna

  23. 1

    Uso isMovingFromParentViewController

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(true)
    
        if self.isMovingFromParentViewController {
            //current viewController is removed from parent
            //do some work
        }
    }
    Podrías explicar un poco más cómo esto demuestra el botón atrás fue aprovechado?
    cambió mi solución
    Esto es simple, pero funciona sólo si está seguro de volver a la vista de cualquier niño (a ver que puede cargar. Si el niño omite este punto de vista se remonta a los padres, el código no va a ser llamado (a la vista de que ya habían desaparecido sin haber movido de los padres). Pero ese es el mismo problema con sólo el manejo de eventos en el disparador de la parte Posterior del botón tal y como pide el OP. Así que esto es una simple respuesta a su pregunta.

    OriginalEl autor herrk

  24. 1

    Swift 4 iOS 11.3 Versión:

    Esto se basa en la respuesta de kgaidis de https://stackoverflow.com/a/34343418/4316579

    No estoy seguro de cuando la extensión dejado de trabajar, pero en el momento de escribir esto (Swift 4), parece que la extensión ya no se ejecutará a menos que se declare UINavigationBarDelegate de conformidad como se describe a continuación.

    Espero que esta ayuda a las personas que se preguntan por qué su extensión ya no funciona.

    extension UINavigationController: UINavigationBarDelegate {
        public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
    
        }
    }

    OriginalEl autor Edward L.

  25. 0

    Para interceptar el botón Atrás, simplemente con una cubierta transparente UIControl y la intersección con la que toca.

    @interface MyViewController : UIViewController
    {
        UIControl   *backCover;
        BOOL        inhibitBackButtonBOOL;
    }
    @end
    
    @implementation MyViewController
    -(void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    
        //Cover the back button (cannot do this in viewWillAppear -- too soon)
        if ( backCover == nil ) {
            backCover = [[UIControl alloc] initWithFrame:CGRectMake( 0, 0, 80, 44)];
    #if TARGET_IPHONE_SIMULATOR
            //show the cover for testing
            backCover.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.15];
    #endif
            [backCover addTarget:self action:@selector(backCoverAction) forControlEvents:UIControlEventTouchDown];
            UINavigationBar *navBar = self.navigationController.navigationBar;
            [navBar addSubview:backCover];
        }
    }
    
    -(void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
    
        [backCover removeFromSuperview];
        backCover = nil;
    }
    
    - (void)backCoverAction
    {
        if ( inhibitBackButtonBOOL ) {
            NSLog(@"Back button aborted");
            //notify the user why...
        } else {
            [self.navigationController popViewControllerAnimated:YES]; //"Back"
        }
    }
    @end
    En el Heads-up: esta respuesta ha sido fusionado en de un duplicado.

    OriginalEl autor Jeff

  26. 0

    La solución que he encontrado hasta ahora no es muy agradable, pero a mí me funciona. Tomando este respuesta, yo también comprobar si estoy haciendo estallar programación o no:

    - (void)viewWillDisappear:(BOOL)animated {
      [super viewWillDisappear:animated];
    
      if ((self.isMovingFromParentViewController || self.isBeingDismissed)
          && !self.isPoppingProgrammatically) {
        //Do your stuff here
      }
    }

    Hay que añadir la propiedad a su controlador y la puso a SÍ antes de hacer estallar programación:

    self.isPoppingProgrammatically = YES;
    [self.navigationController popViewControllerAnimated:YES];

    OriginalEl autor Ferran Maylinch

  27. 0

    Nuevo encontrado la manera de hacerlo :

    Objective-C

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

    Swift

    override func didMoveToParentViewController(parent: UIViewController?) {
        if parent == nil {
            println("Back Pressed")
        }
    }

    OriginalEl autor Ashish Kakkad

  28. 0

    Swift versión de @onegray la respuesta de

    protocol RequestsNavigationPopVerification {
        var confirmationTitle: String { get }
        var confirmationMessage: String { get }
    }
    
    extension RequestsNavigationPopVerification where Self: UIViewController {
        var confirmationTitle: String {
            return "Go back?"
        }
    
        var confirmationMessage: String {
            return "Are you sure?"
        }
    }
    
    final class NavigationController: UINavigationController {
    
        func navigationBar(navigationBar: UINavigationBar, shouldPopItem item: UINavigationItem) -> Bool {
    
            guard let requestsPopConfirm = topViewController as? RequestsNavigationPopVerification else {
                popViewControllerAnimated(true)
                return true
            }
    
            let alertController = UIAlertController(title: requestsPopConfirm.confirmationTitle, message: requestsPopConfirm.confirmationMessage, preferredStyle: .Alert)
    
            alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in
                dispatch_async(dispatch_get_main_queue(), {
                    let dimmed = navigationBar.subviews.flatMap { $0.alpha < 1 ? $0 : nil }
                    UIView.animateWithDuration(0.25) {
                        dimmed.forEach { $0.alpha = 1 }
                    }
                })
                return
            })
    
            alertController.addAction(UIAlertAction(title: "Go back", style: .Default) { _ in
                dispatch_async(dispatch_get_main_queue(), {
                    self.popViewControllerAnimated(true)
                })
            })
    
            presentViewController(alertController, animated: true, completion: nil)
    
            return false
        }
    }

    Ahora en cualquier controlador, sólo se ajustan a RequestsNavigationPopVerification y este comportamiento es adoptado por defecto.

    OriginalEl autor Adam Waite

Dejar respuesta

Please enter your comment!
Please enter your name here