Necesito para ejecutar una acción (vaciado de una matriz), cuando el botón atrás de un UINavigationController se pulsa, mientras que el botón todavía hace que el anterior ViewController en la pila a aparecer. ¿Cómo puedo lograr esto mediante el uso de swift? Ejecutar acción cuando de nuevo el botón de la barra de UINavigationController se pulsa

InformationsquelleAutor StevenR | 2014-12-30

22 Comentarios

  1. 141

    Una opción sería implementar su propio personalizado botón atrás. Usted sería necesario agregar el siguiente código al método viewDidLoad:

    - (void) viewDidLoad {
        [super viewDidLoad];
        self.navigationItem.hidesBackButton = YES;
        UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(back:)];
        self.navigationItem.leftBarButtonItem = newBackButton;
    }
    
    - (void) back:(UIBarButtonItem *)sender {
        //Perform your custom actions
        //...
        //Go back to the previous ViewController
        [self.navigationController popViewControllerAnimated:YES];
    }

    ACTUALIZACIÓN:

    Aquí está la versión para Swift:

        override func viewDidLoad {
            super.viewDidLoad()
            self.navigationItem.hidesBackButton = true
            let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Bordered, target: self, action: "back:")
            self.navigationItem.leftBarButtonItem = newBackButton
        }
    
        func back(sender: UIBarButtonItem) {
            //Perform your custom actions
            //...
            //Go back to the previous ViewController
            self.navigationController?.popViewControllerAnimated(true)
        }

    ACTUALIZACIÓN 2:

    Aquí está la versión para Swift 3:

        override func viewDidLoad {
            super.viewDidLoad()
            self.navigationItem.hidesBackButton = true
            let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(YourViewController.back(sender:)))
            self.navigationItem.leftBarButtonItem = newBackButton
        }
    
        func back(sender: UIBarButtonItem) {
            //Perform your custom actions
            //...
            //Go back to the previous ViewController
            _ = navigationController?.popViewController(animated: true)
        }
    • Este no aparece a la vista anterior del controlador; aparece a la raíz de controlador de vista.
    • ¿Cómo puedo tener una flecha como ordinario botón atrás?
    • Usted puede intentar la siguiente línea en la parte de atrás de la función: [auto.navigationController dismissViewControllerAnimated:SÍ finalización:nil];
    • Para que, por favor, eche un vistazo a la respuesta de abajo
    • Haciendo una sustitución de un sistema de botón para anular una función no es una buena manera. La mejor manera es la respuesta de abajo! stackoverflow.com/a/27715660/2307276
    • Terminé con la creación de un nuevo UIButton, ajuste el título con setTitle y, a continuación, ajuste la imagen con setImage. Usted puede ver esto en el uso con una función en el enlace de más abajo. Línea 42. github.com/andrewlundy/ios-data-passing-tutorial/blob/…

  2. 438

    Reemplazar el botón para uno personalizado como se sugiere en otra respuesta no es, posiblemente, una gran idea como usted perderá el comportamiento predeterminado y estilo.

    Una opción que usted tiene es la aplicación de las viewWillDisappear método en el Controlador de Vista y buscar una propiedad denominada isMovingFromParentViewController. Si esta propiedad es true, significa que el Controlador de Vista está desapareciendo porque ya lo han quitado (apareció).

    Debería ser algo como:

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        if self.isMovingFromParentViewController {
            //Your code...
        }
    }

    En swift 4.2

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        if self.isMovingFromParent {
            //Your code...
        }
    }
    • sí, usted no puede hacer eso. La pregunta no pedir eso. Para ser capaz de detener la acción de ir hacia atrás supongo que usted realmente necesita para reemplazar el botón.
    • Para Swift 3.1: override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if isMovingFromParentViewController { // Your code... } }
    • viewWillDisappear(animated:) va a activar si usted recibe una llamada de teléfono. Esto no es probable que lo que usted desea. Probablemente es mejor usar willMove(toParentViewController:)
    • en Swift 4, la falta de : reemplazar func viewWillDisappear( animación : Bool)
    • Esto debe ser aceptado respuesta. Limpio y sencillo.
    • No, esto es totalmente equivocado, se llama a Este método cuando el botón se presiona y nos aparecerá a ViewController, a continuación, se llama a este método la pregunta es cómo hacer la acción en NavigationItem BackButton haga Clic en. Esto es como la finalización y podemos hacer esto en la ViewWillDisappear. Espero que se lo que estoy diciendo. es que hay alguna forma de hacer clic de botón, a continuación, por favor me dan solución. Gracias
    • desgraciadamente, esto también se llama cuando va a cualquier movimiento de cualquier nuevo controlador de vista… pero necesito capturar sólo el botón atrás y nada más

  3. 53
    override func willMove(toParent parent: UIViewController?)
    {
        super.willMove(toParent: parent)
        if parent == nil
        {
            print("This VC is 'will' be popped. i.e. the back button was pressed.")
        }
    }
    • No trabajo en Swift3/iOS10, consola de impresiones «anidadas pop animación puede resultar dañado en la barra de navegación’.
    • No recibir llamadas en todos los
    • A mí me funciona, gracias.
    • Este es también recibir llamadas cuando se mueve en un nuevo VC, no sólo cuando se va de vuelta.
    • Como por @JozemiteApps comentario, es en el docs se Llama justo antes de que el controlador de vista es añadido o eliminado de un contenedor controlador de vista..
    • así que no es una buena forma de indicar la marcha atrás.
    • Esto debe ser aceptado respuesta. Y cuando parent == nil es cuando nos estamos moviendo atrás a la parent escena
    • UIViewController.willMove(toParent padre: UIViewController?) se llama cuando el ViewController se mueve a un contenedor ViewController, no tiene relación con la navegación.

  4. 27

    Yo era capaz de lograr esto con lo siguiente :

    Swift 3

    override func didMoveToParentViewController(parent: UIViewController?) {
       super.didMoveToParentViewController(parent)
    
       if parent == nil {
          println("Back Button pressed.")
          delegate?.goingBack()
       }           
    }

    Swift 4

    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
    
        if parent == nil {
            debugPrint("Back Button pressed.")
        }
    }

    No hay necesidad de personalizado botón atrás.

    • Esta es la fantásticos. Antiguo comentario, pero todavía funciona con la última Swift.
    • Muchas gracias, @AlexNolasco para añadir Swift4 código!
    • No funciona muy bien.
    • Esto es provocado (falsos positivos) también al desenrollar a partir de la próxima vista controlador (por encima de esta) así que no es realmente de nuevo pulse el botón de detección.
  5. 18

    Si quieres tener de nuevo el botón con la flecha hacia atrás se puede utilizar una imagen y el código de abajo

    backArrow.png Ejecutar acción cuando de nuevo el botón de la barra de UINavigationController se pulsa [email protected] Ejecutar acción cuando de nuevo el botón de la barra de UINavigationController se pulsa [email protected] Ejecutar acción cuando de nuevo el botón de la barra de UINavigationController se pulsa

    override func viewDidLoad() {
        super.viewDidLoad()
        let customBackButton = UIBarButtonItem(image: UIImage(named: "backArrow") , style: .plain, target: self, action: #selector(backAction(sender:)))
        customBackButton.imageInsets = UIEdgeInsets(top: 2, left: -8, bottom: 0, right: 0)
        navigationItem.leftBarButtonItem = customBackButton
    }
    
    func backAction(sender: UIBarButtonItem) {
        //custom actions here
        navigationController?.popViewController(animated: true)
    }
  6. 11

    Si usted está usando navigationController, a continuación, agregue el UINavigationControllerDelegate protocolo a clase y añadir el método delegado de la siguiente manera:

    class ViewController:UINavigationControllerDelegate {
    
        func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController,
    animated: Bool) {
            if viewController === self {
                //do here what you want
            }
        }
    }

    Este método es llamado cada vez que el controlador de navegación se desliza a una nueva pantalla. Si el botón se presiona, el nuevo controlador de vista es ViewController sí mismo.

    • Que se convierte en horrible cuando se utiliza un no NSObjectProtocol clase como delegado.
    • No siempre es llamado cuando se pulsa el botón.
  7. 6

    NO

    override func willMove(toParentViewController parent: UIViewController?) { }

    Esto se llama incluso si usted está segueing a el controlador de vista en el que va a reemplazar este método. En que se verifique si el «parent» es nil de que no es una forma precisa para asegurarse de movimiento espalda para la correcta UIViewController. Para determinar exactamente si la UINavigationController está correctamente navegar de vuelta a la UIViewController que presenta este actual, será necesario ajustarse a la UINavigationControllerDelegate protocolo.

    nota: MyViewController es sólo el nombre de lo que sea UIViewController desea detectar volver a partir.

    1) En la parte superior de su archivo agregar UINavigationControllerDelegate.

    class MyViewController: UIViewController, UINavigationControllerDelegate {

    2) Agregar una propiedad a la clase que siga la pista de la UIViewController que se segueing de.

    class MyViewController: UIViewController, UINavigationControllerDelegate {
    
    var previousViewController:UIViewController

    3) en MyViewController‘s viewDidLoad método de asignar self como el delegado de su UINavigationController.

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.delegate = self
    }

    3) Antes de que salte, asignar el anterior UIViewController como esta propiedad.

    //In previous UIViewController
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "YourSegueID" {
            if let nextViewController = segue.destination as? MyViewController {
                nextViewController.previousViewController = self
            }
        }
    }

    4) Y conforme a un método en MyViewController de la UINavigationControllerDelegate

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        if viewController == self.previousViewController {
            //You are going back
        }
    }
    • Gracias por la amable respuesta! Los lectores de cuidado de la configuración de la UINavigationController del delegado a un determinado controlador de vista; si el controlador de navegación ya tiene un delegado, se corre el riesgo de privar a que otro delegado de devoluciones de llamada de espera. En nuestra aplicación, el UINavigationController del delegado es un objeto compartido (un AppCoordinator) que todos los de la vista de los controladores tienen un puntero.
  8. 5

    En mi caso el viewWillDisappear funcionado mejor. Pero en algunos casos uno tiene que modificar el anterior controlador de vista. Así que aquí está mi solución con el acceso a la anterior controlador de vista de y funciona en Swift 4:

    override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            if isMovingFromParentViewController {
                if let viewControllers = self.navigationController?.viewControllers {
                    if (viewControllers.count >= 1) {
                        let previousViewController = viewControllers[viewControllers.count-1] as! NameOfDestinationViewController
                        //whatever you want to do
                        previousViewController.callOrModifySomething()
                    }
                }
            }
        }
    • -viewDidDisappear (o -viewWillDisappear) será llamado incluso si la vista está siendo cubierto por otro punto de vista del controlador de la vista (no sólo cuando el <de nuevo se pulsa el botón), de ahí la necesidad de revisar isMovingFromParentViewController.
  9. 3

    No es tan difícil como hemos cosa. Acaba de crear un marco para UIButton con claro color de fondo, asignar acción para el botón y colocar sobre el navigationbar botón atrás. Y, por último, eliminar el botón después de su uso.

    Aquí es el Swift 3
    código de ejemplo hecho con UIImage en lugar de UIButton

    override func viewDidLoad() {
        super.viewDidLoad()
        let imageView = UIImageView()
        imageView.backgroundColor = UIColor.clear
        imageView.frame = CGRect(x:0,y:0,width:2*(self.navigationController?.navigationBar.bounds.height)!,height:(self.navigationController?.navigationBar.bounds.height)!)
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(back(sender:)))
        imageView.isUserInteractionEnabled = true
        imageView.addGestureRecognizer(tapGestureRecognizer)
        imageView.tag = 1
        self.navigationController?.navigationBar.addSubview(imageView)
        }

    escribir el código que se necesita para ser ejecutado

    func back(sender: UIBarButtonItem) {
    
        //Perform your custom actions}
        _ = self.navigationController?.popViewController(animated: true)
    
        }

    Quitar la subvista después de la acción que se realiza

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        for view in (self.navigationController?.navigationBar.subviews)!{
            if view.tag == 1 {
                view.removeFromSuperview()
            }
        }
    • wow esto fue creativo 🙂
    • Gracias tio . 🙂
    • ¿Cómo crear el estado cuando toca?
    • Esto no parece funcionar en iOS 11. No cuando el UIImageView el color de fondo es claro. Establecer en un color diferente y funciona.
    • Podemos definir un UIImageView con colores claros, establecer el marco, asignar tapgesture y en cualquier lugar de la pantalla. Entonces, ¿por qué no podemos colocarlo sobre una barra de navegación. Para ser sincero, no voy a recomendar lo que yo escribí . Si hay un problema definitivamente no es una razón, pero no es el color de la materia. Olvida el código de seguir la lógica de la u va a tener éxito. 🙂
  10. 3

    En Swift de Xcode 5 y 10.2

    Por favor no personalizar el botón de la barra de elemento, utilice este comportamiento por defecto.

    No hay necesidad de viewWillDisappear, no hay necesidad de personalizado BarButtonItem etc…

    Es mejor para detectar cuando la VC es removido de su padre.

    De utilizar cualquiera de estas dos funciones

    override func willMove(toParent parent: UIViewController?) {
        super.willMove(toParent: parent)
        if parent == nil {
            callStatusDelegate?.backButtonClicked()//Here write your code
        }
    }
    
    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        if parent == nil {
            callStatusDelegate?.backButtonClicked()//Here write your code
        }
    }

    Si quieres dejar de comportamiento por defecto del botón atrás, a continuación, agregue personalizado BarButtonItem.

  11. 2

    Swift 3:

    override func didMove(toParentViewController parent: UIViewController?) {
        super.didMove(toParentViewController: parent)
    
        if parent == nil{
            print("Back button was clicked")
        }
    }
    • -hizo/willMove(toParentViewController:) es posiblemente mejor que la comprobación de isMovingTfromParentViewController en viewWillDisappear ya que sólo es llamado cuando el controlador de vista es en realidad el cambio de los padres (no cuando la vista está cubierto por otro VC de la vista), Pero la más «correcta» la solución es implementar el UINavigationController método de delegado. Tenga cuidado, sin embargo; si el NavigationController ya tiene un delegado, se corre el riesgo de privar a que otro delegado de devoluciones de llamada de espera.
  12. 2

    Swift 4.2:

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        if self.isMovingFromParent {
            //Your code...
    
        }
    }
  13. 1

    Probar esta .

    self.navigationItem.leftBarButtonItem?.target = "methodname"
    func methodname ( ) {            
      //   enter code here
    }

    Probar en este también.

    override func viewWillAppear(animated: Bool) {
      //empty your array
    }
    • No funciona para mí
  14. 1

    Como entiendo que quieres vaciar tu array como pulsar su botón de atrás y pop a su anterior ViewController let su Array la que ha cargado en esta pantalla es

    let settingArray  = NSMutableArray()
    @IBAction func Back(sender: AnyObject) {
        self. settingArray.removeAllObjects()
        self.dismissViewControllerAnimated(true, completion: nil)
    } 
  15. 1
        override public func viewDidLoad() {
             super.viewDidLoad()
             self.navigationController?.navigationBar.topItem?.title = GlobalVariables.selectedMainIconName
             let image = UIImage(named: "back-btn")
    
             image = image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
    
            self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(Current[enter image description here][1]ViewController.back) )
        }
    
        func back() {
          self.navigationController?.popToViewController( self.navigationController!.viewControllers[ self.navigationController!.viewControllers.count - 2 ], animated: true)
        }
    • Por favor, explique su código
  16. 1

    acaba de hacer control + arrastrar el elemento de la barra de debajo de func. trabajo como encanto

    @IBAction func done(sender: AnyObject) {
        if((self.presentingViewController) != nil){
            self.dismiss(animated: false, completion: nil)
            print("done")
        }
    }

    Ejecutar acción cuando de nuevo el botón de la barra de UINavigationController se pulsa

    • El código ha funcionado para mí, gracias!!
  17. 1
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        if self.isMovingToParent {
    
            //your code backView
        }
    }
  18. 1

    Antes de salir de corriente controlador necesito mostrar alerta. Así que lo hice de esta manera:

    1. Añadir extensión a UINavigationController con UINavigationBarDelegate
    2. Agregar selector para su controlador de navigationShouldPopOnBack(finalización:)

    Ha funcionado)

    JS:

    extension UINavigationController: UINavigationBarDelegate {
        public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
            if let items = navigationBar.items, viewControllers.count < items.count {
                return true
            }
            
            let clientInfoVC = topViewController as? ClientInfoVC
            if clientInfoVC?.responds(to: #selector(clientInfoVC?.navigationShouldPopOnBack)) ?? false {
                clientInfoVC?.navigationShouldPopOnBack(completion: { isAllowPop in
                    if isAllowPop {
                        DispatchQueue.main.async {
                            self.popViewController(animated: true)
                        }
                    }
                })
            }
            
            DispatchQueue.main.async {
                self.popViewController(animated: true)
            }
            
            return false
        }
    }

    JS:

    @objc func navigationShouldPopOnBack(completion: @escaping (Bool) -> ()) {
            let ok = UIAlertAction(title: R.string.alert.actionOk(), style: .default) { _ in
                completion(true)
            }
            let cancel = UIAlertAction(title: R.string.alert.actionCancel(), style: .cancel) { _ in
                completion(false)
            }
            let alertController = UIAlertController(title: "", message: R.string.alert.contractMessage(), preferredStyle: .alert)
            alertController.addAction(ok)
            alertController.addAction(cancel)
            present(alertController, animated: true, completion: nil)
        }

  19. 0

    Que he logrado esta llamando/reemplazar viewWillDisappear y, a continuación, acceder a la pila de la navigationController como este:

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    
        let stack = self.navigationController?.viewControllers.count
    
        if stack >= 2 {
            //for whatever reason, the last item on the stack is the TaskBuilderViewController (not self), so we only use -1 to access it
            if let lastitem = self.navigationController?.viewControllers[stack! - 1] as? theViewControllerYoureTryingToAccess {
                //hand over the data via public property or call a public method of theViewControllerYoureTryingToAccess, like
                lastitem.emptyArray()
                lastitem.value = 5
            }
        }
    }
  20. 0

    Esto es cómo lo resolví por mi propio problema

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationItem.leftBarButtonItem?.action = #selector(self.back(sender:))
        self.navigationItem.leftBarButtonItem?.target = self
    }
    
    @objc func back(sender: UIBarButtonItem) {
    
    }
  21. 0

    Aquí es la más sencilla posible Swift 5 solución que no requiere que usted para crear una costumbre botón atrás y renunciar a todo lo que UINavigationController botón izquierdo funcionalidad que usted obtenga de forma gratuita.

    Como Brandon Un recomienda anterior, tiene necesidad de implementar UINavigationControllerDelegate en el controlador de vista que se desee interactuar antes de volver a él. Una buena manera es crear un desenredo segue que puede realizar manualmente o automáticamente y reutilizar el mismo código de una costumbre botón ok o el botón atrás.

    Primero, hacer que su controlador de vista de interés (el que se quiere detectar volviendo a) un delegado de la navegación controlador en su viewDidLoad:

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.delegate = self
    }

    Segundo, añadir una extensión en la parte inferior del archivo que reemplaza navigationController(willShow:animated:)

    extension PickerTableViewController: UINavigationControllerDelegate {
    
        func navigationController(_ navigationController: UINavigationController,
                                  willShow viewController: UIViewController,
                                  animated: Bool) {
    
            if let _ = viewController as? EditComicBookViewController {
    
                let selectedItemRow = itemList.firstIndex(of: selectedItemName)
                selectedItemIndex = IndexPath(row: selectedItemRow!, section: 0)
    
                if let selectedCell = tableView.cellForRow(at: selectedItemIndex) {
                    performSegue(withIdentifier: "PickedItem", sender: selectedCell)
                }
            }
        }
    }

    Ya que tu pregunta se incluye un UITableViewController, he incluido una manera de obtener la ruta del índice de la fila que el usuario aprovechado.

Dejar respuesta

Please enter your comment!
Please enter your name here