如何在一次操作中从 UINavigationController 中弹出一个视图并将其替换为另一个视图?
我有一个应用程序,我需要从 UINavigationController 堆栈中删除一个视图并将其替换为另一个视图。 情况是,第一个视图创建一个可编辑项目,然后用该项目的编辑器替换自身。 当我在第一个视图中执行明显的解决方案时:
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];
[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];
我得到了非常奇怪的行为。 通常会出现编辑器视图,但如果我尝试使用导航栏上的后退按钮,我会看到额外的屏幕,有些是空白的,有些只是搞砸了。 标题也变得随机。 就像导航堆栈完全被冲洗一样。
解决这个问题的更好方法是什么?
谢谢, 马特
I have an application where I need to remove one view from the stack of a UINavigationController and replace it with another. The situation is that the first view creates an editable item and then replaces itself with an editor for the item. When I do the obvious solution within the first view:
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];
[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];
I get very strange behavior. Usually the editor view will appear, but if I try to use the back button on the nav bar I get extra screens, some blank, and some just screwed up. The title becomes random too. It is like the nav stack is completely hosed.
What would be a better approach to this problem?
Thanks,
Matt
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我发现您根本不需要手动弄乱
viewControllers
属性。 基本上有两个棘手的事情。self
当前不在导航控制器的堆栈上,则self.navigationController
将返回nil
。 因此,在您失去对它的访问权限之前,请将其保存到局部变量中。保留
(并正确地释放
)self
,否则拥有您所在方法的对象将被释放,从而导致奇怪的情况。做好准备后,就可以像平常一样弹出和推送了。 此代码将立即用另一个控制器替换顶部控制器。
在最后一行中,如果您将
animated
更改为YES
,那么新屏幕将实际以动画方式显示,而您刚刚弹出的控制器将以动画方式显示。 看起来很不错!I've discovered you don't need to manually mess with the
viewControllers
property at all. Basically there are 2 tricky things about this.self.navigationController
will returnnil
ifself
is not currently on the navigation controller's stack. So save it to a local variable before you lose access to it.retain
(and properlyrelease
)self
or the object who owns the method you are in will be deallocated, causing strangeness.Once you do that prep, then just pop and push as normal. This code will instantly replace the top controller with another.
In that last line if you change the
animated
toYES
, then the new screen will actually animate in and the controller you just popped will animate out. Looks pretty nice!下面的方法对我来说似乎更好,并且也适用于 ARC:
The following approach seems nicer to me, and also works well with ARC:
根据经验,您将不得不直接修改 UINavigationController 的
viewControllers
属性。 像这样的东西应该有效:注意:我将保留/释放更改为保留/自动释放,因为这通常更健壮 - 如果保留/释放之间发生异常,您将泄漏自身,但自动释放会处理这个问题。
From experience, you're going to have to fiddle with the UINavigationController's
viewControllers
property directly. Something like this should work:Note: I changed the retain/release to a retain/autorelease as that's just generally more robust - if an exception occurs between the retain/release you'll leak self, but autorelease takes care of that.
经过大量努力(并调整了 Kevin 的代码),我终于弄清楚了如何在从堆栈中弹出的视图控制器中执行此操作。 我遇到的问题是,在我从控制器数组中删除最后一个对象后, self.navigationController 返回 nil 。 我认为这是由于文档中的这一行
UIViewController 上的实例方法navigationController
“如果视图控制器位于其堆栈中,则仅返回导航控制器。”
我认为一旦当前视图控制器从堆栈中删除,它的 navigationController 方法将返回 nil。
这是调整后的有效代码:
After much effort (and tweaking the code from Kevin), I finally figured out how to do this in the view controller that is being popped from the stack. The problem that I was having was that self.navigationController was returning nil after I removed the last object from the controllers array. I think it was due to this line in the documentation for
UIViewController on the instance method navigationController
"Only returns a navigation controller if the view controller is in its stack."
I think that once the current view controller is removed from the stack, its navigationController method will return nil.
Here is the adjusted code that works:
谢谢,这正是我所需要的。 我还将其放入动画中以获得页面卷曲:
0.6 持续时间很快,适合 3GS 及更新版本,0.8 对于 3G 来说仍然有点太快了..
Johan
Thanks, this was exactly what I needed. I also put this in an animation to get the page curl:
0.6 duration is fast, good for 3GS and newer, 0.8 is still a bit too fast for 3G..
Johan
如果您想通过 popToRootViewController 显示任何其他视图控制器,那么您需要执行以下操作:
现在,您以前的所有堆栈将被删除,并且将使用您所需的 rootViewController 创建新堆栈。
If you want to show any other view controller by popToRootViewController then you need to do following:
Now, all your previous stack will be removed and new stack will be created with your required rootViewController.
我最近不得不做类似的事情,并基于迈克尔斯的回答我的解决方案。 就我而言,我必须从导航堆栈中删除两个视图控制器,然后添加一个新的视图控制器。 呼唤
twice, worked fine in my case.
<代码> <代码>
>
I had to do a similar thing recently and based my solution on Michaels answer. In my case I had to remove two View Controllers from the Navigation Stack and then add a new View Controller on. Calling
twice, worked fine in my case.
这个 UINavigationController 实例方法可能会起作用...
弹出视图控制器,直到指定的视图控制器是顶部视图控制器,然后更新显示。
This
UINavigationController
instance method might work...Pops view controllers until the specified view controller is the top view controller and then updates the display.
这是另一种不需要直接弄乱 viewControllers 数组的方法。 检查控制器是否已弹出,如果是,则将其推入。
Here is another approach that doesn't require directly messing with the viewControllers array. Check if the controller has been pop'd yet, if so push it.
我最喜欢的方法是使用 UINavigationController 上的类别。 以下内容应该有效:
UINavigationController+Helpers.h
#import
UINavigationController+Helpers.m
#import "UINavigationController+Helpers.h"
然后从你的视图控制器中,你可以用一个新的视图替换顶视图,如下所示:
My favorite way to do it is with a category on UINavigationController. The following should work:
UINavigationController+Helpers.h
#import
UINavigationController+Helpers.m
#import "UINavigationController+Helpers.h"
Then from your view controller, you can replace the top view with a new by like this:
您可以检查导航视图控制器数组,该数组为您提供在导航堆栈中添加的所有视图控制器。 通过使用该数组,您可以向后导航到特定的视图控制器。
You can check with navigation view controllers array which you give you all view controllers that you have added in navigation stack. By using that array you can back navigate to specific view controller.
对于 monotouch / xamarin IOS:
在 UISplitViewController 类中;
For monotouch / xamarin IOS:
inside UISplitViewController class;
或者,
您可以使用
category
来避免self.navigationController
在popViewControllerAnimated
只是弹出和推送后为
nil
,它是易于理解,不需要访问viewControllers
....在你的 ViewController 中
Alternatively,
You can use
category
to avoidself.navigationController
to benil
afterpopViewControllerAnimated
just pop and push, it's easy to understand, don't need to access
viewControllers
....In your ViewController
不完全是答案,但在某些情况下可能会有所帮助(例如我的):
如果您需要弹出视图控制器 C 并转到 B(堆栈外)而不是 A(C 下面的那个),则可以在之前推送 B C,并将所有 3 个都放入堆栈中。 通过保持 B 推送不可见,并选择是仅弹出 C 还是同时弹出 C 和 B,您可以达到相同的效果。
初始问题
A-> C(我想弹出 C 并显示 B,出栈)
可能的解决方案
A-> B(推隐形)-> C(当我弹出C时,我选择显示B或也弹出它)
Not exactly the answer but might be of help in some scenarios (mine for example):
If you need to pop viewcontroller C and go to B (out of stack) instead of A (the one bellow C), it's possible to push B before C, and have all 3 on the stack. By keeping the B push invisible, and by choosing whether to pop only C or C and B altogether, you can achieve the same effect.
initial problem
A -> C (I want to pop C and show B, out of stack)
possible solution
A -> B (pushed invisible) -> C (when I pop C, I choose to show B or also pop it)
我使用这个解决方案来保留动画。
I use this solution to keep the animation.