Estoy tratando de sobrescribir la acción predeterminada del botón Atrás en un controlador de navegación. Le proporcioné a un objetivo una acción en el botón personalizado. Lo extraño es que al asignarlo, aunque el atributo de botón de retroceso no les presta atención, solo muestra la vista actual y vuelve a la raíz:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle: @"Servers"
style:UIBarButtonItemStylePlain
target:self
action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;
Tan pronto como lo configuré leftBarButtonItem
en el navigationItem
, llama a mi acción, sin embargo, el botón parece simple y redondo en lugar del de flecha hacia atrás:
self.navigationItem.leftBarButtonItem = backButton;
¿Cómo puedo hacer que llame a mi acción personalizada antes de volver a la vista raíz? ¿Hay alguna forma de sobrescribir la acción de retroceso predeterminada, o hay un método que siempre se llama al salir de una vista ( viewDidUnload
no hace eso)?
Respuestas:
Intente poner esto en el controlador de vista donde desea detectar la prensa:
fuente
if (find(self.navigationController!.viewControllers as! [UIViewController],self)==nil)
He implementado la extensión UIViewController-BackButtonHandler . No necesita subclasificar nada, solo colóquelo en su proyecto y anule el
navigationShouldPopOnBackButton
método enUIViewController
clase:Descargue la aplicación de muestra .
fuente
navigationBar:shouldPopItem:
no es un método privado ya que es parte delUINavigationBarDelegate
protocolo.YES
)? o lo hará en el futuro? subclasificar es probablemente una opción más seguraNO
el botón de retroceso permanece en un estado deshabilitado (visualmente, porque todavía recibe y reacciona a eventos táctiles). Lo solucioné agregando unaelse
declaración alshouldPop
cheque y recorriendo las subvistas de la barra de navegación, y estableciendo elalpha
valor nuevamente en 1 si es necesario dentro de un bloque de animación: gist.github.com/idevsoftware/9754057A diferencia de Amagrammer, dijo, es posible. Tienes que subclasificar tu
navigationController
. Le expliqué todo aquí (incluido el código de ejemplo).fuente
Versión rápida:
(de https://stackoverflow.com/a/19132881/826435 )
En su controlador de vista, simplemente se ajusta a un protocolo y realiza cualquier acción que necesite:
Luego cree una clase, digamos
NavigationController+BackButton
, y simplemente copie y pegue el siguiente código:fuente
shouldPopOnBackButtonPress
debe llamarse siempre que no haya errores.performSomeActionOnThePressOfABackButton
es solo un método inventado que no existe.performSomeActionOnThePressOfABackButton
en mi controlador para ejecutar una acción específica cuando se presiona el botón de retroceso, pero este método nunca se llamó, la acción es un retorno normalUINavigationController
,navigationBar.delegate
se establece en el controlador de navegación. Entonces los métodos DEBEN ser llamados. Sin embargo, en Swift, no puedo hacer que se llamen, incluso en una subclase. Sin embargo, conseguí que se llamaran en Objective-C, por lo que solo usaría la versión Objective-C por ahora. Podría ser un error de Swift.No es posible hacerlo directamente. Hay un par de alternativas:
UIBarButtonItem
que se valida al tocar y hacer estallar si la prueba pasaUITextField
método de delegado, como-textFieldShouldReturn:
, que se llama después de presionar el botónReturn
oDone
en el tecladoLa desventaja de la primera opción es que no se puede acceder al estilo de flecha hacia la izquierda del botón Atrás desde un botón de barra personalizado. Por lo tanto, debe usar una imagen o ir con un botón de estilo normal.
La segunda opción es buena porque recupera el campo de texto en el método delegado, por lo que puede orientar su lógica de validación al campo de texto específico enviado al método de devolución de llamada delegado.
fuente
Por algunas razones, la solución mencionada por @HansPinckaers no era adecuada para mí, pero encontré una manera más fácil de tocar el botón Atrás, y quiero fijar esto aquí en caso de que esto pueda evitar horas de engaños para alguien más. El truco es realmente fácil: simplemente agregue un botón UIB transparente como una subvista a su UINavigationBar, y configure sus selectores para él como si fuera el botón real. Aquí hay un ejemplo usando Monotouch y C #, pero la traducción a Objective-C no debería ser demasiado difícil de encontrar.
Dato curioso: para fines de prueba y para encontrar buenas dimensiones para mi botón falso, configuré su color de fondo en azul ... ¡Y se muestra detrás del botón Atrás! De todos modos, todavía atrapa cualquier toque que apunte al botón original.
fuente
Esta técnica le permite cambiar el texto del botón "atrás" sin afectar el título de ninguno de los controladores de vista ni ver el cambio del texto del botón atrás durante la animación.
Agregue esto al método init en el controlador de vista de llamada :
fuente
La manera más fácil
Puede usar los métodos delegados de UINavigationController. Se
willShowViewController
llama al método cuando se presiona el botón Atrás de su VC. Haga lo que quiera cuando se presione Btn.fuente
Aquí está mi solución Swift. En su subclase de UIViewController, anule el método navigationShouldPopOnBackButton.
fuente
Encontró una solución que conserva el estilo del botón de retroceso también. Agregue el siguiente método a su controlador de vista.
Ahora proporcione una funcionalidad según sea necesario en el siguiente método:
Todo lo que hace es cubrir el botón de retroceso con un botón transparente;)
fuente
========================================
Sobre la base de las respuestas anteriores con UIAlert en Swift5 en un asíncrono camino
En su controlador
fuente
No creo que esto sea posible, fácilmente. La única forma en que creo evitar esto es hacer su propia imagen de flecha del botón de retroceso para colocarla allí. Al principio fue frustrante para mí, pero veo por qué, por razones de coherencia, se dejó de lado.
Puede acercarse (sin la flecha) creando un botón normal y ocultando el botón de retroceso predeterminado:
fuente
Hay una manera más fácil simplemente subclasificando el método delegado del
UINavigationBar
y anula elShouldPopItem
método .fuente
La solución de onegray no es segura. De acuerdo con los documentos oficiales de Apple, https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html , debemos evitar hacerlo.
"Si el nombre de un método declarado en una categoría es el mismo que un método en la clase original, o un método en otra categoría en la misma clase (o incluso una superclase), el comportamiento no está definido en cuanto a qué implementación de método se utiliza en tiempo de ejecución. Es menos probable que esto sea un problema si usa categorías con sus propias clases, pero puede causar problemas al usar categorías para agregar métodos a las clases estándar de Cocoa o Cocoa Touch ".
fuente
Usando Swift:
fuente
Aquí está la versión Swift 3 de la respuesta de @oneway para capturar el evento del botón de retroceso de la barra de navegación antes de que se active. Como
UINavigationBarDelegate
no se puede utilizarUIViewController
, debe crear un delegado que se activará cuandonavigationBar
shouldPop
se llame.Y luego, en su controlador de vista, agregue la función de delegado:
Me he dado cuenta de que a menudo queremos agregar un controlador de alertas para que los usuarios decidan si quieren regresar. Si es así, siempre se puede
return false
en lanavigationShouldPopOnBackButton()
función y cerrar el controlador de vista al hacer algo como esto:fuente
Value of type 'UIViewController' has no member 'navigationShouldPopOnBackButton'
cuando trato de compilar su código, para la líneaif vc.responds(to: #selector(v...
Además, elself.topViewController
devuelve un opcional y también hay una advertencia para eso.let vc = self.topViewController as! MyViewController
y parece funcionar bien hasta ahora. Si cree que es un cambio correcto, puede editar el código. Además, si siente que no debe hacerse, me alegrará saber por qué. Gracias por este código. Probablemente debería escribir una publicación de blog sobre esto, ya que esta respuesta está oculta según los votos.MyViewController
posible que no se ajusteBackButtonDelegate
. En lugar de forzar el desenvolvimiento, debe hacerloguard let vc = self.topViewController as? MyViewController else { return true }
para evitar un posible choque.guard let vc = self.topViewController as? MyViewController else { self.popViewController(animated: true) return true }
para asegurarse de que la pantalla se mueva a la página correcta en caso de que no se pueda emitir correctamente. Ahora entiendo que lanavigationBar
función se llama en todos los VC y no solo en el controlador de vista donde existe este código. ¿Puede ser bueno actualizar el código en su respuesta también? Gracias.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 cuándo la extensión dejó de funcionar, pero al momento de escribir esto (Swift 4), parece que la extensión ya no se ejecutará a menos que declare la conformidad UINavigationBarDelegate como se describe a continuación.
Espero que esto ayude a las personas que se preguntan por qué su extensión ya no funciona.
fuente
Al utilizar el objetivo y las variables de acción que está dejando actualmente 'nulo', debería poder conectar sus diálogos de guardado para que se invoquen cuando el botón esté "seleccionado". Cuidado, esto puede activarse en momentos extraños.
Estoy de acuerdo principalmente con Amagrammer, pero no creo que sea tan difícil hacer que el botón con la flecha sea personalizado. Simplemente cambiaría el nombre del botón Atrás, tomaría una captura de pantalla, photoshop el tamaño del botón necesario, y que esa sea la imagen en la parte superior de su botón.
fuente
Puede intentar acceder al elemento del botón derecho de NavigationBars y establecer su propiedad de selector ... aquí hay una referencia UIBarButtonItem referencia , otra cosa si este trabajo que no funcionará es establecer el elemento del botón derecho de la barra de navegación en un elemento UIBarButtonItem personalizado que crear y configurar su selector ... espero que esto ayude
fuente
Para un formulario que requiere la entrada del usuario como este, recomendaría invocarlo como un "modal" en lugar de parte de su pila de navegación. De esa manera, tienen que ocuparse de los negocios en el formulario, luego puede validarlo y descartarlo con un botón personalizado. Incluso puedes diseñar una barra de navegación que se vea igual que el resto de tu aplicación pero que te dé más control.
fuente
Para interceptar el botón Atrás, simplemente cúbralo con un control UIC transparente e intercepte los toques.
fuente
Al menos en Xcode 5, hay una solución simple y bastante buena (no perfecta). En IB, arrastre un elemento del botón de barra fuera del panel Utilidades y suéltelo en el lado izquierdo de la barra de navegación donde estaría el botón Atrás. Establezca la etiqueta en "Atrás". Tendrá un botón de funcionamiento que puede vincular a su IBAction y cerrar su viewController. Estoy haciendo un trabajo y luego desencadenando una desconexión y funciona perfectamente.
Lo que no es ideal es que este botón no obtiene la flecha <y no lleva adelante el título de VC anterior, pero creo que esto se puede administrar. Para mis propósitos, configuré el nuevo botón Atrás para que sea un botón "Listo" para que su propósito sea claro.
También terminas con dos botones Atrás en el navegador IB, pero es bastante fácil etiquetarlo para mayor claridad.
fuente
Rápido
fuente
Este enfoque funcionó para mí (pero el botón "Atrás" no tendrá el signo "<"):
fuente
Versión rápida de la respuesta de @ onegray
Ahora, en cualquier controlador, simplemente cumpla
RequestsNavigationPopVerification
y este comportamiento se adopta por defecto.fuente
Utilizar
isMovingFromParentViewController
fuente
viewDidDisappear
. De esa manera, solo se disparará una vez que la vista haya desaparecido definitivamente.Sin embargo, la respuesta de @William es correcta, si el usuario inicia un gesto de deslizar hacia atrás
viewWillDisappear
, se llama al método e inclusoself
no estará en la pila de navegación (es decir,self.navigationController.viewControllers
no contendráself
), incluso si el deslizamiento no se ha completado y el controlador de vista no aparece realmente. Por lo tanto, la solución sería:Deshabilite el gesto de deslizar hacia atrás
viewDidAppear
y solo permita usar el botón Atrás, usando:O simplemente use
viewDidDisappear
en su lugar, de la siguiente manera:fuente
La solución que he encontrado hasta ahora no es muy agradable, pero funciona para mí. Tomando esta respuesta , 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:
fuente
Encontramos una nueva forma de hacerlo:
C objetivo
Rápido
fuente