UINavigationController popToRootViewController, а затем сразу же нажмите новый вид
У меня есть tabBarController с двумя вкладками, первый из которых содержит экземпляр NavigatorController. NavigatorController инициируется с помощью настраиваемого viewController "peersViewController", который отображает все сетевые одноранговые узлы в tableView. При выборе однорангового узла экземпляр "FilesListViewController" (который перечисляет файлы в каталоге c: \) помещается в стек навигационной системы.
В этом файлеListViewController у меня есть кнопка, позволяющая ему перейти в каталог документов. Для этого я подключил интерфейс для вызова метода пути gotoDirectory: (NSString *) в корневом контроллере:
- (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];
}
Однако, когда я нажимаю эту кнопку, диспетчер навигации выводил мое представление на контроллер корневого представления, но затем созданный экземпляр FilesListViewController не появился. Из журнала я знаю, что пользовательский метод initWithFiles действительно был вызван, и сетевые файлы действительно получили имена файлов.
В этом что-то другое. Я попытался щелкнуть вторую вкладку, а затем вернуться к первой вкладке и huala! мне нужны имена файлов. Похоже, что данные и файлыListViewController действительно были введены в стек навигатора, но дисплей не обновился, а застрял на экране rootViewController (peersViewController).
Я делаю что-то неправильно?
-. Бен
- Отредактировано через 15 минут после публикации вопроса. Я нашел обходное решение, но это беспокоит меня, что поп, а затем нажмите не работает.
- (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];
}
Похоже, что navigationController должен быть обойден таким образом, и мне, вероятно, придется выпустить все viewControllers, которые были в исходном стеке. Однако это работает на симуляторе iphone 3.0.
Если я использую этот код, как это сделать, как следует освобождать память? должен ли я получить исходный NSArray контроллеров view и освободить все?
Ответы
Ответ 1
Проблема и решение этой проблемы на самом деле чрезвычайно просто.
Вызов [self.navigationController popToRootViewControllerAnimated:YES]
устанавливает self.navigationController
в nil
. Когда вы впоследствии вызываете [self.navigationController pushViewController:someOtherViewController]
, вы эффективно отправляете сообщение в nil
, которое ничего не делает.
Чтобы обходной путь, просто настройте локальную ссылку на navigationController и используйте это вместо:
UINavigationController * navigationController = self.navigationController;
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];
Как указано Джейсоном, popToRootViewController должен выполняться без анимации, чтобы это работало правильно.
Благодарим вас за jpimbert на форумах Apple, указав это.
Ответ 2
У меня очень похожая проблема (но без использования вкладки).
У меня есть три viewController: main (root), форма и результат.
когда стек UINavigationController
"main → result"
на btnClick я делаю popToRootViewControllerAnimated, затем нажмите formViewCtrl.
чтобы иметь
"main → form"
Значок заголовка навигационной панели и обратной кнопки верны и вызывается событие formViewCtrl.
НО, я все еще вижу основной вид.
Вот мое "решение"
После выполнения какого-то теста я обнаружил, что без анимации перейти к rootViwCtrl этой работе отлично. Поэтому я использую анимацию только для того, чтобы нажимать viewCtrl.
iPhone 3.0, проблема найдена на устройстве и симуляторе.
Если у меня есть что-то новое, я буду обновлять/комментировать мой пост.
Ответ 3
Я вижу, что этот вопрос о появлении в корне, а затем нажатии нового ViewController довольно распространен, и этот пост просматривается много, поэтому я хотел добавить свой бит, чтобы помочь другим новым парням, особенно тем, кто использует Xcode 4 и раскадровки.
В Xcode 4 у вас есть раскадровка. Скажем, у вас есть эти контроллеры представлений: HomeViewController, FirstPageViewController, SecondPageViewController. Обязательно нажмите на каждый из них и назовите их идентификаторы, перейдя в панель "Утилиты" → "Инспектор атрибутов". Мы скажем, что они называются Home, First и Second.
Вы являетесь домом, затем переходите к First, затем вы хотите, чтобы вы могли перейти на Second и иметь возможность нажать кнопку "Назад", чтобы вернуться в Home. Для этого вы хотите изменить свой код в FirstPageViewController.
Чтобы расширить пример, сделайте кнопку в FirstPageViewController в раскадровке. Ctrl-перетащите эту кнопку в FirstPageViewController.m. В этом случае следующий код достигнет желаемого результата:
// 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];
В принципе, вы захватываете контроллеры представлений, упорядочиваете их в стеке в том порядке, в котором хотите, а затем используя навигационный контроллер, используйте этот стек для навигации. Это альтернатива толчкам и выскакиванию.
Ответ 4
Я нашел обходной путь, но я не могу объяснить, почему он работает:
1. Сначала нажмите необходимый контроллер.
2. Затем нажмите на тот, который вы хотите.
Это совершенно нелогично, но это работает для моего дела.
Для того, чтобы все было ясно, я использую его в следующем сценарии:
Первый экран → Переход к экрану загрузки → Второй экран
Когда я нахожусь на втором экране, я не хочу иметь экран загрузки в стеке, и когда я вернусь, я должен перейти на первый экран.
С уважением,
Веско Колев
Ответ 5
Ответ на Nick Street отлично работает, если вы хотите popToRootViewController и затем нажмите другой VC.
VC1 → VC2 → VC3: нажмите кнопку возврата с VC3 = > VC2, затем VC1, здесь OK
Однако, когда VC1 толкает VC2, который, в свою очередь, подталкивает VC3, то возврат к VC1 непосредственно из VC3 не работает по желанию:
Я реализовал в VC3 -(void)viewWillDisappear:(BOOL)animated
:
-(void)viewWillDisappear:(BOOL)animated{
...
[self.navigationController popToRootViewControllerAnimated:YES];
}
Я также попытался реализовать его в кнопке "Назад", тот же результат: при нажатии кнопки "Назад" из VC3, чтобы вернуться к VC1: он ломается. Фактический VC - VC1, но панель навигации по-прежнему VC2. Играя с другими комбинациями, я получаю VC1 navBar на VC2. Общий беспорядок.
Лода упомянул о сроках. Я думаю, что главная проблема здесь. Я пробовал несколько вещей, так что, может быть, я что-то упустил, но вот что мне помогло, наконец:
В VC3:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// notify VC2
[[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self];
}
В 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];
}
Конечно, сделайте необходимую очистку.
Здесь важна таймер. Если 0, он ломается. 0.5, похоже, в порядке.
Это отлично работает для меня. Немного тяжело, но я не смог найти ничего, что могло бы сделать трюк.
Ответ 6
Фактически вы можете сохранить анимацию "Назад", а затем анимацию "Вперед", в основном задерживая анимацию push до завершения поп-анимации. Вот пример:
(Примечание. У меня есть переменная NSString, называемая "transitionTo" в моем приложении appDelegate, которая первоначально была установлена на @"")... Сначала установите эту переменную в NSString, которую вы можете обнаружить позже. Затем вытащите контроллер, чтобы дать вам хороший переход на экран к корню:
appDelegate.transitionTo = @"Another";
[detailNavigationController popToRootViewControllerAnimated:YES];
Затем внутри класса rootviewcontroller используйте метод 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];
}
Итак, в основном, поп в корень... когда переход заканчивается на "viewDidAppear"... затем нажмите следующий вид. Мне удалось сохранить переменную, чтобы указать вам, с каким видом вы хотите перейти (с @", что означает не делать переход в случае, когда я хочу остаться на этом экране).