我怎么能从一个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
我发现你根本不需要手动搞乱viewControllers
属性。 基本上有2个棘手的事情。
- 如果
self
当前不在导航控制器的堆栈中,self.navigationController
将返回nil
。 因此,保存到本地variables,然后再失去访问权限。 - 您必须
retain
(并正确release
)self
或拥有您所在方法的对象将被释放,从而导致奇怪。
一旦你做了准备,然后就像平常一样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它)