font color ios iphone objective-c segue uistoryboardsegue

ios - color - ion-toolbar



En lugar de presionar, ¿cómo reemplazar el controlador de visualización(o eliminarlo de la pila de navegación)? (13)

¿Qué tal esto :) Ahora es una vieja pregunta, pero esto funcionará como un encanto:

UIViewController *destinationController = [[UIViewController alloc] init]; UINavigationController *newNavigation = [[UINavigationController alloc] init]; [newNavigation setViewControllers:@[destinationController]]; [[[UIApplication sharedApplication] delegate] window].rootViewController = newNavigation;

Tengo una pequeña aplicación para iPhone , que usa un controlador de navegación para mostrar 3 vistas (aquí a fullscreen ):

Primero muestra una lista de redes sociales (Facebook, Google+, etc.):

Luego muestra un cuadro de diálogo OAuth que solicita credenciales:

Y (después de eso, en el mismo UIWebView ) para obtener permisos:

Finalmente, muestra el último controlador de vista con los detalles del usuario (en la aplicación real, este será el menú donde se puede iniciar el juego de varios jugadores):

Todo esto funciona bien, pero tengo un problema cuando el usuario quiere volver y seleccionar otra red social:

El usuario toca el botón Atrás y, en lugar de mostrarse en la primera vista, se muestra el segundo y vuelve a solicitar las credenciales / permisos de OAuth.

¿Qué puedo hacer aquí? Xcode 5.0.2 muestra una opción muy limitada para los segmentos - push , modal (que no puedo usar, porque oscurece la barra de navegación necesaria para mi juego) y personalizados .

Soy un novato en programación iOS, pero antes desarrollé una aplicación móvil Adobe AIR y allí fue posible 1) reemplazar la vista en lugar de presionar y 2) eliminar una vista innecesaria de la pila de navegación.

¿Cómo hacer lo mismo en una aplicación nativa por favor?



Como se mencionó en las respuestas anteriores a pop no animado y luego a push animado, no se verá muy bien porque el usuario verá el proceso real. Te recomiendo primero push animado y luego eliminar la vc anterior. Al igual que:

extension UINavigationController { func replaceCurrentViewController(with viewController: UIViewController, animated: Bool) { pushViewController(viewController, animated: animated) let indexToRemove = viewControllers.count - 2 if indexToRemove >= 0 { viewControllers.remove(at: indexToRemove) } } }


En swift3 crea un segue -add identifier -add y establece en segue (storyboard) una clase de storyboard personalizada desde el archivo cocoatouch -En la clase personalizada anula perform ()

override func perform() { let sourceViewController = self.source let destinationController = self.destination let navigationController = sourceViewController.navigationController // Pop to root view controller (not animated) before pushing if self.identifier == "your identifier"{ navigationController?.popViewController(animated: false) navigationController?.pushViewController(destinationController, animated: true) } }

-También debe anular un método en su controlador de vista de origen

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { return false }


Esto funcionó para mí en Swift 3:

class ReplaceSegue: UIStoryboardSegue { override func perform() { if let navVC = source.navigationController { navVC.pushViewController(destination, animated: true) } else { super.perform() } } }


La transición personalizada no funcionó para mí, ya que tenía un controlador de vista Splash y quería reemplazarlo. Como solo había un controlador de vista en la lista, popToRootViewController aún dejaba el Splash en la pila. Usé el siguiente código para reemplazar el controlador único

-(void)perform { UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; UIViewController *destinationController = (UIViewController*)[self destinationViewController]; UINavigationController *navigationController = sourceViewController.navigationController; [navigationController setViewControllers:@[destinationController] animated:YES]; }

y ahora en Swift 4:

class ReplaceSegue: UIStoryboardSegue { override func perform() { source.navigationController?.setViewControllers([destination], animated: true) } }

y ahora en Swift 2.0

class ReplaceSegue: UIStoryboardSegue { override func perform() { sourceViewController.navigationController?.setViewControllers([destinationViewController], animated: true) } }


Lo que realmente debería hacer es presentar de manera modal un UINavigationController contenga la red social UIViewControllers de su Menú UIViewController (que se puede incrustar en un UINavigationController si lo desea). Luego, una vez que un usuario se ha autenticado, descarta la red social UINavigationController , mostrando su Menú UIViewController nuevamente.


Para ampliar los diversos segmentos anteriores, esta es mi solución. Tiene las siguientes ventajas:

  • Puede trabajar en cualquier lugar de la pila de vistas, no solo en la vista superior (no estoy seguro de si realmente se necesita o si es técnicamente posible de activar, pero está ahí).
  • No provoca una transición O pop al controlador de vista anterior antes de mostrar el reemplazo, solo muestra el nuevo controlador con una transición natural, con la navegación trasera en la misma navegación trasera del controlador de origen.

Código Segue:

- (void)perform { // Grab Variables for readability UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; UIViewController *destinationController = (UIViewController*)[self destinationViewController]; UINavigationController *navigationController = sourceViewController.navigationController; // Get a changeable copy of the stack NSMutableArray *controllerStack = [NSMutableArray arrayWithArray:navigationController.viewControllers]; // Replace the source controller with the destination controller, wherever the source may be [controllerStack replaceObjectAtIndex:[controllerStack indexOfObject:sourceViewController] withObject:destinationController]; // Assign the updated stack with animation [navigationController setViewControllers:controllerStack animated:YES]; }


Para este problema, creo que la respuesta es simple como

  1. Obtenga la matriz de controladores de vista desde NavigationController
  2. Eliminar el último ViewController (controlador de vista actual)
  3. Inserte uno nuevo al fin
  4. A continuación, configure la matriz de ViewControllers de nuevo en navigationController como a continuación:

    if let navController = self.navigationController { let newVC = DestinationViewController(nibName: "DestinationViewController", bundle: nil) var stack = navController.viewControllers stack.remove(at: stack.count - 1) // remove current VC stack.insert(newVC, at: stack.count) // add the new one navController.setViewControllers(stack, animated: true) // boom! }

funciona perfectamente con Swift 3.

Espero que ayude a algunos chicos nuevos.

Aclamaciones.


Podrías usar un segue personalizado: para hacerlo necesitas crear una clase subclasificando UIStoryboardSegue (ejemplo MyCustomSegue), y luego puedes anular el "perform" con algo como esto

-(void)perform { UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; UIViewController *destinationController = (UIViewController*)[self destinationViewController]; UINavigationController *navigationController = sourceViewController.navigationController; // Pop to root view controller (not animated) before pushing [navigationController popToRootViewControllerAnimated:NO]; [navigationController pushViewController:destinationController animated:YES]; }

En este punto, vaya a Interface Builder, seleccione segue "custom" y coloque el nombre de su clase (ejemplo MyCustomSegue)


Usa el código de abajo del controlador de la última vista Puedes utilizar otro botón o ponerlo en tu lugar en lugar de cancelar el botón que he usado

- (void)viewDidLoad { [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss:)]; self.navigationItemSetting.leftBarButtonItem = cancelButton; } - (IBAction)dismissSettings:(id)sender { // your logout code for social media selected [self.navigationController popToRootViewControllerAnimated:YES]; }


Usar la transición de desenrollado sería la solución más adecuada para este problema. Estoy de acuerdo con Lauro.

Aquí hay una breve explicación para configurar un desenlace de desenrollar de los detalles ViewController [o viewController3] a myAuthViewController [o viewController1]

Esta es esencialmente la forma en que realizaría un desenrollado a través del código.

  • Implemente un método IBAction en viewController al que desee desenrollar (en este caso, viewController1). El nombre del método puede ser algo tan largo que requiera un argumento del tipo UIStoryboardSegue.

    @IBAction func unwindToMyAuth(segue: UIStoryboardSegue) { println("segue with ID: %@", segue.Identifier) }

  • Enlaza este método en viewController (3) desde el que deseas desenrollar. Para vincular, haga clic con el botón derecho (toque doble) en el ícono de salida en la parte superior de viewController, en este punto se mostrará el método ''unwindToMyAuth'' en el cuadro emergente. Haga clic en Control desde este método hasta el primer icono, el ícono viewController (también presente en la parte superior del viewController, en la misma fila que el ícono de salida). Seleccione la opción ''manual'' que aparece.

  • En el esquema del documento, para la misma vista (viewController3), seleccione la transición de desenrollado que acaba de crear. Vaya al inspector atribuido y asigne un identificador único para este segue de desenrollado. Ahora tenemos un segue genérico de desenrollado listo para ser utilizado.

  • Ahora, la transición de desenrollado se puede realizar como cualquier otra transición desde el código.

    performSegueWithIdentifier("unwind.to.myauth", sender: nil)

Este enfoque lo llevará de viewController3 a viewController1 sin la necesidad de eliminar viewController2 de la jerarquía de navegación.

A diferencia de otros segmentos, los segmentos de desenrollado no instancian un controlador de vista, solo van a un controlador de vista existente en la jerarquía de navegación.


la versión rápida 2 de ima747 respuesta:

override func perform() { let navigationController: UINavigationController = sourceViewController.navigationController!; var controllerStack = navigationController.viewControllers; let index = controllerStack.indexOf(sourceViewController); controllerStack[index!] = destinationViewController navigationController.setViewControllers(controllerStack, animated: true); }

Como lo mencionó, tiene las siguientes ventajas:

  • Puede trabajar en cualquier lugar de la pila de vistas, no solo en la vista superior (no estoy seguro de si realmente se necesita o si es técnicamente posible de activar, pero está ahí).
  • No provoca una transición O pop al controlador de vista anterior antes de mostrar el reemplazo, solo muestra el nuevo controlador con una transición natural, con la navegación trasera en la misma navegación trasera del controlador de origen.