Necesito realizar algunas acciones cuando el botón Atrás (volver a la pantalla anterior, volver a la vista principal) se presiona en una barra de navegación.
¿Hay algún método que pueda implementar para capturar el evento y activar algunas acciones para pausar y guardar datos antes de que desaparezca la pantalla?
iphone
objective-c
ios
xcode
ewok
fuente
fuente
Respuestas:
ACTUALIZACIÓN: Según algunos comentarios, la solución en la respuesta original no parece funcionar en ciertos escenarios en iOS 8+. No puedo verificar que ese sea realmente el caso sin más detalles.
Para aquellos de ustedes, sin embargo, en esa situación hay una alternativa. Es posible detectar cuándo se abre un controlador de vista anulando
willMove(toParentViewController:)
. La idea básica es que se abre un controlador de vista cuandoparent
es asínil
.Consulte "Implementación de un controlador de vista de contenedor" para obtener más detalles.
Desde iOS 5 descubrí que la forma más fácil de lidiar con esta situación es usar el nuevo método
- (BOOL)isMovingFromParentViewController
:- (BOOL)isMovingFromParentViewController
tiene sentido cuando empuja y hace estallar controladores en una pila de navegación.Sin embargo, si presenta controladores de vista modal, debe usar
- (BOOL)isBeingDismissed
en su lugar:Como se señaló en esta pregunta , puede combinar ambas propiedades:
Otras soluciones se basan en la existencia de a
UINavigationBar
. En cambio, me gusta más mi enfoque porque desacopla las tareas requeridas para realizar de la acción que activó el evento, es decir, presionar un botón de retroceso.fuente
self.isMovingFromParentViewController
tiene un valor VERDADERO cuando estoy desplegando la pila de navegación mediante programaciónpopToRootViewControllerAnimated
, sin tocar el botón Atrás. ¿Debería rechazar su respuesta? (el sujeto dice "botón 'atrás' se presiona en una barra de navegación")override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) if isMovingFromParentViewController(){ println("back button pressed") } }
-viewDidDisappear:
ya que es posible que obtenga un-viewWillDisappear:
sin un-viewDidDisappear:
(como cuando comienza a deslizar para descartar un elemento del controlador de navegación y luego cancelar ese deslizamiento.)Mientras
viewWillAppear()
yviewDidDisappear()
se llaman cuando se toca el botón Atrás, también se llaman en otros momentos. Vea el final de la respuesta para más información sobre eso.Usando UIViewController.parent
La detección del botón Atrás se realiza mejor cuando el VC se elimina de su padre (el NavigationController) con la ayuda de
willMoveToParentViewController(_:)
ORdidMoveToParentViewController()
Si padre es nulo, el controlador de vista se saca de la pila de navegación y se descarta. Si padre no es nulo, se agrega a la pila y se presenta.
Intercambiar
willMove
paradidMove
y verificación self.parent para hacer el trabajo después del controlador de vista es despedido.Deteniendo el despido
Tenga en cuenta que verificar el padre no le permite "pausar" la transición si necesita hacer algún tipo de guardado asíncrono. Para hacer eso, podría implementar lo siguiente. El único inconveniente aquí es que pierdes el elegante botón de retroceso animado / estilo iOS. También tenga cuidado aquí con el gesto de deslizamiento interactivo. Use lo siguiente para manejar este caso.
Más sobre la vista aparecerá / apareció
Si no obtuvo el
viewWillAppear
viewDidDisappear
problema, veamos un ejemplo. Digamos que tiene tres controladores de vista:Vamos a seguir las llamadas en la
detailVC
medida que avanza de lalistVC
asettingsVC
y de nuevo alistVC
List> Detail (push detailVC)
Detail.viewDidAppear
<- apareceDetail> Settings (push settingsVC)
Detail.viewDidDisappear
<- desaparecerY a medida que retrocedemos ...
Configuración> Detalle (pop settingsVC)
Detail.viewDidAppear
<- apareceDetalle> Lista (pop detailVC)
Detail.viewDidDisappear
<- desapareceTenga en cuenta que
viewDidDisappear
se llama varias veces, no solo al retroceder, sino también al avanzar. Para una operación rápida que puede desearse, pero para una operación más compleja como una llamada de red para guardar, puede que no.fuente
didMoveToParantViewController:
debe trabajar cuando la vista ya no es visible. Útil para iOS7 con el InteractiveGesutre_ = self.navigationController?.popViewController(animated: true)
, por lo que no solo se llama al presionar el botón Atrás. Estoy buscando una llamada que funcione solo cuando se presiona Atrás.Primer método
Segundo método
fuente
Los que afirman que esto no funciona están equivocados:
Eso funciona bien Entonces, ¿qué está causando el mito generalizado de que no es así?
El problema parece deberse a una implementación incorrecta de un método diferente , a saber, que la implementación de
willMove(toParent:)
Olvidó llamarsuper
.Si implementa
willMove(toParent:)
sin llamarsuper
, entoncesself.isMovingFromParent
seráfalse
y el uso deviewWillDisappear
parecerá fallar. No falló; lo rompiste.NOTA: El problema real suele ser que el segundo controlador de vista detecte que el primer controlador de vista apareció. Consulte también la discusión más general aquí: ¿La detección unificada de UIViewController "se convirtió en la primera"?
EDITAR Un comentario sugiere que esto debería ser
viewDidDisappear
más queviewWillDisappear
.fuente
true
para el gesto emergente de deslizamiento interactivo, desde el borde izquierdo del controlador de vista, incluso si el deslizamiento no lo destacó por completo. Entonces, en lugar de registrarlowillDisappear
, hacerlodidDisappear
funciona.He jugado (o peleado) con este problema durante dos días. En mi opinión, el mejor enfoque es crear una clase de extensión y un protocolo, como este:
Esto funciona porque
UINavigationController
recibirá una llamadanavigationBar:shouldPopItem:
cada vez que aparezca un controlador de vista. Allí detectamos si se presionó la tecla de retroceso o no (cualquier otro botón). Lo único que tiene que hacer es implementar el protocolo en el controlador de vista donde se presiona la parte posterior.Recuerde abrir manualmente el controlador de vista
backButtonPressedSel
, si todo está bien.Si ya ha subclasificado
UINavigationViewController
e implementadonavigationBar:shouldPopItem:
, no se preocupe, esto no interferirá con ello.También te puede interesar desactivar el gesto de retroceso.
fuente
Esto funciona para mí en iOS 9.3.x con Swift:
A diferencia de otras soluciones aquí, esto no parece desencadenarse inesperadamente.
fuente
Para que conste, creo que esto es más de lo que estaba buscando ...
fuente
Como se
purrrminator
dice, la respuestaelitalon
no es del todo correcta, yayour stuff
que se ejecutaría incluso cuando se activa el controlador mediante programación.La solución que he encontrado hasta ahora no es muy agradable, pero funciona para mí. Además de lo
elitalon
dicho, también verifico si estoy apareciendo programáticamente o no:Debe agregar esa propiedad a su controlador y establecerla en SÍ antes de aparecer mediante programación:
¡Gracias por tu ayuda!
fuente
La mejor manera es usar los métodos de delegado UINavigationController
Con esto, puede saber qué controlador muestra el UINavigationController.
fuente
He resuelto este problema agregando un UIControl a la barra de navegación en el lado izquierdo.
Y debe recordar eliminarlo cuando la vista desaparezca:
¡Eso es todo!
fuente
Puede usar la devolución de llamada del botón Atrás, de esta manera:
para la versión rápida, puede hacer algo como en el ámbito global
Debajo de uno pones en el controlador de vista donde quieres controlar la acción del botón Atrás:
fuente
navigationShouldPopOnBackButton
viene? No es parte de la API pública.Como dijo Coli88, debe verificar el protocolo UINavigationBarDelegate.
De una manera más general, también puede usar
- (void)viewWillDisapear:(BOOL)animated
para realizar un trabajo personalizado cuando la vista retenida por el controlador de vista actualmente visible está a punto de desaparecer. Desafortunadamente, esto cubriría tanto los casos de empuje como los de pop.fuente
Para Swift con un UINavigationController:
fuente
La respuesta de 7ynk3r estuvo muy cerca de lo que utilicé al final, pero necesitaba algunos ajustes:
fuente
Debe consultar el protocolo UINavigationBarDelegate . En este caso, es posible que desee utilizar el método navigationBar: shouldPopItem:
fuente
self.navigationController.isMovingFromParentViewController ya no funciona en iOS8 y 9 Yo uso:
fuente
(RÁPIDO)
finalmente encontramos la solución ... el método que estábamos buscando es "willShowViewController", que es el método delegado de UINavigationController
fuente
MyViewController
aPushedController
.