我怎么能从一个UINavigationControllerpopup一个视图,并用另一个操作中的另一个replace它?

我有一个应用程序,我需要从UINavigationController的堆栈中删除一个视图,并将其replace为另一个视图。 情况是,第一个视图创build一个可编辑的项目,然后用该项目的编辑器replace自己。 当我在第一个视图中做出明显的解决scheme时:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo]; [self retain]; [self.navigationController popViewControllerAnimated: NO]; [self.navigationController pushViewController: mevc animated: YES]; [self release]; 

我感到非常奇怪的行为。 通常会出现编辑器视图,但是如果我尝试使用导航栏上的后退button,我会得到额外的屏幕,一些空白,有些只是搞砸了。 标题也变得随机。 这就像导航堆栈是完全水封的。

什么会是更好的方法来解决这个问题?

谢谢,Matt

15 Solutions collect form web for “我怎么能从一个UINavigationControllerpopup一个视图,并用另一个操作中的另一个replace它?”

我发现你根本不需要手动搞乱viewControllers属性。 基本上有2个棘手的事情。

  1. 如果self当前不在导航控制器的堆栈中, self.navigationController将返回nil 。 因此,保存到本地variables,然后再失去访问权限。
  2. 您必须retain (并正确releaseself或拥有您所在方法的对象将被释放,从而导致奇怪。

一旦你做了准备,然后就像平常一样popup和推动。 这段代码将立即replace顶部控制器。

 // locally store the navigation controller since // self.navigationController will be nil once we are popped UINavigationController *navController = self.navigationController; // retain ourselves so that the controller will still exist once it's popped off [[self retain] autorelease]; // Pop this controller and replace with another [navController popViewControllerAnimated:NO]; [navController pushViewController:someViewController animated:NO]; 

在最后一行中,如果将animated更改为YES ,那么新的屏幕实际上就会生成animation并且刚刚popup的控制器将会animation化。 看起来不错!

以下方法对我来说似乎更好,并且与ARC一起工作良好:

 UIViewController *newVC = [[UIViewController alloc] init]; // Replace the current view controller NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]]; [viewControllers removeLastObject]; [viewControllers addObject:newVC]; [[self navigationController] setViewControllers:viewControllers animated:YES]; 

从经验中,你将不得不直接摆弄UINavigationController的viewControllers属性。 像这样的东西应该工作:

 MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo]; [[self retain] autorelease]; NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease]; [controllers removeLastObject]; self.navigationController.viewControllers = controllers; [self.navigationController pushViewController:mevc animated: YES]; 

注意:我将保留/释放更改为保留/自动释放,因为这通常更健壮 – 如果在保留/释放之间发生exception,您将自我泄漏,但autorelease处理此问题。

经过很多努力(并从凯文调整代码),我终于想出了如何在视图控制器中从堆栈中popup。 我遇到的问题是,我从控制器数组中删除最后一个对象后,self.navigationController返回零。 我认为这是由于实例方法navigationController上的UIViewController的文档中的这一行“如果视图控制器在其堆栈中,只返回一个导航控制器。

我认为,一旦当前的视图控制器从堆栈中删除,其navigationController方法将返回零。

这是调整后的代码:

 UINavigationController *navController = self.navigationController; MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo]; NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease]; [controllers removeLastObject]; navController.viewControllers = controllers; [navController pushViewController:mevc animated: YES]; 

谢谢,这正是我所需要的。 我也把它放在一个animation来获得页面curl:

  MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo]; UINavigationController *navController = self.navigationController; [[self retain] autorelease]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 0.7]; [UIView setAnimationTransition:<#UIViewAnimationTransitionCurlDown#> forView:navController.view cache:NO]; [navController popViewControllerAnimated:NO]; [navController pushViewController:mevc animated:NO]; [UIView commitAnimations]; 

0.6的持续时间很快,对于3GS而言较好,对于3G来说0.8仍然有点过快。

约翰

如果你想通过popToRootViewController显示任何其他视图控制器,那么你需要做以下事情:

  UIViewController *newVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:[NSBundle mainBundle]]; NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]]; [viewControllers removeAllObjects]; [viewControllers addObject:newVC]; [[self navigationController] setViewControllers:viewControllers animated:NO]; 

现在,你以前的所有堆栈都将被删除,并且新的堆栈将被创build为你需要的rootViewController。

我最近不得不做了类似的事情,并根据我的解决scheme在Michaels的答案。 在我的情况下,我不得不从导航堆栈中删除两个视图控制器,然后添加一个新的视图控制器。 调用

  [controllers removeLastObject]; 

两次,在我的情况下罚款。

 UINavigationController *navController = self.navigationController; // retain ourselves so that the controller will still exist once it's popped off [[self retain] autorelease]; searchViewController = [[SearchViewController alloc] init]; NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease]; [controllers removeLastObject]; // In my case I want to go up two, then push one.. [controllers removeLastObject]; navController.viewControllers = controllers; NSLog(@"controllers: %@",controllers); controllers = nil; [navController pushViewController:searchViewController animated: NO]; 

这个UINavigationController实例方法可能工作…

popup视图控制器,直到指定的视图控制器是顶部视图控制器,然后更新显示。

 - (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated 

这是另一种不需要直接搞乱viewControllers数组的方法。 检查控制器是否已经popup,如果是这样的话。

 TasksViewController *taskViewController = [[TasksViewController alloc] initWithNibName:nil bundle:nil]; if ([navigationController.viewControllers indexOfObject:taskViewController] == NSNotFound) { [navigationController pushViewController:taskViewController animated:animated]; } else { [navigationController popToViewController:taskViewController animated:animated]; } 
 NSMutableArray *controllers = [self.navigationController.viewControllers mutableCopy]; for(int i=0;i<controllers.count;i++){ [controllers removeLastObject]; } self.navigationController.viewControllers = controllers; 

我最喜欢的方式是在UINavigationController上的一个类别。 以下应该工作:

UINavigationController + Helpers.h #import

 @interface UINavigationController (Helpers) - (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller; @end 

UINavigationController的+ Helpers.m
#import“UINavigationController + Helpers.h”

 @implementation UINavigationController (Helpers) - (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller { UIViewController* topController = self.viewControllers.lastObject; [[topController retain] autorelease]; UIViewController* poppedViewController = [self popViewControllerAnimated:NO]; [self pushViewController:controller animated:NO]; return poppedViewController; } @end 

然后从你的视图控制器,你可以用一个新的replace顶视图像这样:

 [self.navigationController replaceTopViewControllerWithViewController: newController]; 

你可以检查导航视图控制器数组,你给你所有的视图控制器,你已经添加到导航堆栈。 通过使用该数组,您可以返回导航到特定的视图控制器。

对于monotouch / xamarin IOS:

在UISplitViewController类里面;

 UINavigationController mainNav = this._navController; //List<UIViewController> controllers = mainNav.ViewControllers.ToList(); mainNav.ViewControllers = new UIViewController[] { }; mainNav.PushViewController(detail, true);//to have the animation 

或者,

你可以使用category来避免在popViewControllerAnimated之后使用popViewControllerAnimated

只是popup和推,很容易理解,不需要访问viewControllers ….

 // UINavigationController+Helper.h @interface UINavigationController (Helper) - (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated; @end // UINavigationController+Helper.m @implementation UINavigationController (Helper) - (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated { UIViewController *v =[self popViewControllerAnimated:NO]; [self pushViewController:viewController animated:animated]; return v; } @end 

在你的ViewController中

 // #import "UINavigationController+Helper.h" // invoke in your code UIViewController *v= [[MyNewViewController alloc] init]; [self.navigationController popThenPushViewController:v animated:YES]; RELEASE_SAFELY(v); 

不完全是答案,但可能在某些情况下(例如我的)的帮助:

如果您需要popup视图控制器C并转到B(堆栈外)而不是A(C中的一个),则可以在C之前推B,并且堆栈中全部为3。 通过保持B推送不可见,并且通过select仅popupC还是C和B,可以达到相同的效果。

最初的问题A – > C(我想popupC和显示B,出栈)

可能的解决方法A – > B(推送不可见) – > C(当我popupC,我select显示B或也popup它)