iphone - change - set root view controller programmatically swift
UINavigationController popToRootViewController e inmediatamente presione una nueva vista (6)
El problema y la solución a este problema es en realidad extremadamente simple.
Al llamar [self.navigationController popToRootViewControllerAnimated:YES]
establece self.navigationController
en nil
. Cuando posteriormente llama a [self.navigationController pushViewController:someOtherViewController]
está enviando efectivamente un mensaje a nil
, que no hace nada.
Para solucionar el problema, simplemente configure una referencia local al navigationController y use eso en su lugar:
UINavigationController * navigationController = self.navigationController;
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];
Como lo indica Jason, el popToRootViewController debe ejecutarse sin animación para que esto funcione correctamente.
Gracias a jpimbert en los foros de Apple por señalar esto.
Tengo un tabBarController con dos pestañas, la primera de las cuales contiene una instancia de NavigatorController. NavigatorController se inicia con un viewController personalizado "peersViewController" que enumera todos los pares de la red en un tableView. Al seleccionar un igual, una instancia de "FilesListViewController" (que enumera los archivos en el directorio c: /) se inserta en la pila de navigationController.
En este filesListViewController tengo un botón que le permite navegar para decir el directorio de documentos. Para hacer esto, conecté la interfaz para llamar a un método gotoDirectory: (NSString *) en el rootViewController:
- (void)gotoDirectory:(NSString*)path {
[[self navigationController] popToRootViewControllerAnimated:YES];
NSArray *files = [self getFilesFromPeerAtPath:path];
FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
[[self navigationController] pushViewController:filesVC animated:YES];
[filesVC release];
}
Sin embargo, cuando presioné ese botón, el control de navegación hizo estallar mi vista en el controlador de vista raíz, pero luego no apareció el FilesListViewController que instalé. Desde el registro, sé que el método personalizado initWithFiles fue llamado y que los elementos de red sucedieron para obtener los nombres de los archivos.
Algo más está loco por esto. Intenté hacer clic en la segunda pestaña y luego en volver a la primera pestaña, y ¡huala! Los nombres de archivo que necesitaba están ahí. Parece que los datos y los archivosListViewController se insertaron en la pila de navigatorController, pero la pantalla no se actualizó sino que se atascó en la pantalla de rootViewController (peersViewController).
¿Estoy haciendo algo mal?
--Ben
- Editado como 15 minutos después de publicar la pregunta. Encontré una solución alternativa, pero me molesta que el pop no funcione.
- (void)gotoDirectory:(NSString*)path {
PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0];
[[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]];
FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
[[self navigationController] pushViewController:filesVC animated:YES];
[filesVC release];
}
No parece que el controlador de navegación deba ser eludido de esta manera, y probablemente tendría que liberar todos los controladores de vista que estaban en la pila original. Sin embargo, esto funciona en el simulador de iphone 3.0.
Sin embargo, si estoy usando este código, ¿cómo debería manejarse la versión de memoria? ¿Debo obtener la NSArray original de los controladores de vista y liberar todo?
En realidad, puede mantener la animación "Volver", seguida de la animación "Ir hacia adelante" básicamente retrasando la animación de inserción hasta que se complete la animación emergente. Aquí hay un ejemplo:
(Nota: tengo una variable NSString llamada "transitionTo" en mi appDelegate que inicialmente está configurada en @ "") ... Primero, establezca esa variable en una NSString que pueda detectar más adelante. Luego, abra el controlador para devolverle una buena transición de pantalla a la raíz:
appDelegate.transitionTo = @"Another";
[detailNavigationController popToRootViewControllerAnimated:YES];
Luego, dentro de la clase rootviewcontroller, use el método viewDidAppear:
-(void)viewDidAppear:(BOOL)animated
{
AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate;
if([appDelegate.transitionTo isEqualToString:@"Another"])
{
[self transitionToAnotherView];
appDelegate.transitionTo = @"";
}
}
-(void)transitionToAnotherView
{
// Create and push new view controller here
AnotherViewController *controller = [[AnotherViewController alloc] init];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil];
[self.navigationItem setBackBarButtonItem:backButton];
[[self navigationController] pushViewController:controller animated:YES];
}
Básicamente, vaya a la raíz ... cuando la transición termine en "viewDidAppear" ... luego presione la siguiente vista. Resulta que mantuve una variable para decirle a qué vista desea hacer la transición (con @ "", lo que significa que no debe hacer una transición en el caso de que quiera permanecer en esta pantalla).
Encontré una solución alternativa, pero no puedo explicar por qué funciona: 1. Primero presione el controlador necesario. 2. Luego pop a la que desea.
Esto es totalmente ilógico, pero funciona para mi caso. Solo para aclarar las cosas, lo uso en el siguiente escenario: Primera pantalla -> Va a la pantalla de carga -> Segunda pantalla Cuando estoy en la segunda pantalla, no quiero tener la pantalla de carga en la pila y cuando vuelva a hacer clic debería ir a la Primera Pantalla.
Saludos, Vesko Kolev
La respuesta de Nick Street funciona muy bien si desea popToRootViewController y posteriormente empujar otro VC.
VC1 -> VC2 -> VC3: presione el botón Atrás desde VC3 => VC2, luego VC1, aquí OK
Sin embargo, cuando VC1 empuja a VC2, que a su vez empuja a VC3, volver al VC1 directamente desde VC3 no funciona como se desea:
He implementado en VC3''s -(void)viewWillDisappear:(BOOL)animated
:
-(void)viewWillDisappear:(BOOL)animated{
...
[self.navigationController popToRootViewControllerAnimated:YES];
}
También intenté implementarlo en el "botón Atrás", mismo resultado: al presionar el botón Atrás de VC3 para volver a VC1: se rompe. El VC real es VC1, pero la barra de navegación sigue siendo VC2. Jugando con otras combinaciones, obtengo la barra de navegación de VC1 en VC2. Desastre total.
Loda mencionó algo sobre el tiempo. Creo que ese es el problema principal aquí. He intentado algunas cosas, así que tal vez me esté perdiendo algo aquí, pero esto es lo que me funcionó, por fin:
En VC3:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// notify VC2
[[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self];
}
En VC2:
-(void)viewDidLoad {
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backFromV3)
name:@"BackFromV3"
object:nil];
}
-(void)backFromV3{
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:@selector(backToRootViewController)
userInfo:nil
repeats:NO];
}
-(void)backToVC1 {
self.navigationItem.rightBarButtonItem = nil;
[self.navigationController popToRootViewControllerAnimated:YES];
}
Por supuesto, hacer la limpieza necesaria.
El temporizador es crítico aquí. Si es 0, se rompe. 0.5 parece estar bien.
Eso funciona perfectamente para mí. Un poco pesado, pero no he podido encontrar nada que haga el truco.
Tengo un problema muy similar (pero sin usar pestaña).
viewController : main(root)
tres viewController : main(root)
, forma y resultado. cuando la pila UINavigationController
es
"main -> result"
en un btnClick hago un popToRootViewControllerAnimated
luego una pulsación de formViewCtrl. para tener
"main -> form"
el título de la barra de navegación y la etiqueta del botón Atrás son correctos y se llama al evento formViewCtrl. PERO, todavía veo la vista principal.
Aquí está mi "solución"
Después de hacer algunas pruebas, descubrí que sin la animación para ir al rootViwCtrl esto funciona bien . Así que solo uso la animación para empujar viewCtrl.
iPhone 3.0, problema encontrado en dispositivo y simulador.
Si tengo algo nuevo, actualizaré / comentaré mi publicación.
Veo que esta pregunta sobre saltar a la raíz y luego empujar un nuevo ViewController es bastante frecuente, y este post se ve mucho, así que quería agregar mi parte para ayudar a otros nuevos chicos, especialmente aquellos que usan Xcode 4 y un guión gráfico. .
En Xcode 4, tienes un guión gráfico. Digamos que tiene estos controladores de vista: HomeViewController, FirstPageViewController, SecondPageViewController. Asegúrese de hacer clic en cada uno de ellos y nombrar sus identificadores en el panel Utilidades -> Inspector de atributos. Diremos que se llaman Inicio, Primero y Segundo.
Usted está en Inicio, luego va a Primero, luego desea poder ir a Segundo y puede presionar el botón Atrás para volver a Inicio. Para hacer esto, desea cambiar su código en FirstPageViewController.
Para ampliar el ejemplo, cree un botón en FirstPageViewController en el guión gráfico. Ctrl-arrastre ese botón en FirstPageViewController.m. Allí, el siguiente código logrará el resultado deseado:
// Remember to add #import "SecondPageViewController.h" at the top
SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"];
UINavigationController *navigationController = self.navigationController;
NSArray *array = [navigationController viewControllers];
// [array objectAtIndex:0] is the root view controller
NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil];
[navigationController setViewControllers:viewControllersStack animated:YES];
Básicamente, estás agarrando los controladores de vista, ordenándolos en una pila en el orden que deseas, y luego haciendo que el controlador de navegación use esa pila para la navegación. Es una alternativa a empujar y hacer estallar.