ios 如何弹回根视图控制器然后推送到不同的视图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11820934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pop back to root view controller but then push to a different view?
提问by Ryan
I am writing a simple application that has 3 view controllers. The root view controller is an item listing
, basic table view. Off of this view controller, I push two different view controllers based on some user interaction - a create item
view controller or a view item
view controller.
我正在编写一个具有 3 个视图控制器的简单应用程序。根视图控制器是一个item listing
基本的表视图。在这个视图控制器之外,我根据一些用户交互推送了两个不同的视图控制器 -create item
视图控制器或view item
视图控制器。
So, the storyboard segues just look like a V, or something.
所以,storyboard segues 只是看起来像一个 V,或者什么的。
On my create item
view controller, I would like it to pop back to the root view controller when the user creates a new item, but then push to the view item
controller so that I can look at the newly created item.
在我的create item
视图控制器上,我希望它在用户创建新项目时弹回根视图控制器,然后推送到view item
控制器以便我可以查看新创建的项目。
I can't seem to get this to work. It's easy enough to pop back to the root view controller, but I'm unable to push that view item
controller.
我似乎无法让它发挥作用。弹回根视图控制器很容易,但我无法推送该view item
控制器。
Any ideas? I've pasted my code, below. The pop function works, but the new view never appears.
有任何想法吗?我在下面粘贴了我的代码。pop 功能有效,但新视图从未出现。
- (void) onSave:(id)sender {
CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation];
// format the thread object dictionary
NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ];
NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location };
// send the new thread to the api server
[[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread"
parameters:thread
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// init thread object
Thread *thread = [[Thread alloc] initWithDictionary:responseObject];
// init view thread controller
ThreadViewController *viewThreadController = [[ThreadViewController alloc] init];
viewThreadController.thread = thread;
[self.navigationController popToRootViewControllerAnimated:NO];
[self.navigationController pushViewController:viewThreadController animated:YES];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self.navigationController popToRootViewControllerAnimated:YES];
}];
}
采纳答案by CocoaEv
An easy way to accomplish what you want to do is to build some simple logic into your main root view controllers -(void)viewWillAppear method and use a delegate callback to flip the logic switch. basically a "back reference" to the root controller. here is a quick example.
完成您想要做的事情的一种简单方法是将一些简单的逻辑构建到您的主根视图控制器 -(void)viewWillAppear 方法中,并使用委托回调来翻转逻辑开关。基本上是对根控制器的“反向引用”。这是一个简单的例子。
main root controller (consider this controller a) - well call it controllerA set a property to keep track of the jump status
主根控制器(考虑这个控制器 a) - 称它为 controllerA 设置一个属性来跟踪跳转状态
@property (nonatomic) BOOL jumpNeeded;
setup some logic in
设置一些逻辑
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed");
if (self.jumpNeeded) {
NSLog(@"jumping");
self.jumpNeeded = NO;
[self performSegueWithIdentifier:@"controllerC" sender:self];
}
}
Now, in your main root controller,when a tableview row is selected do something like this when pushing to controllerB in your tableView did select method
Now, in your main root controller,when a tableview row is selected do something like this when pushing to controllerB in your tableView did select method
[self performSegueWithIdentifer@"controllerB" sender:self];
then implement your prepare for segue method
然后实现你的准备转场方法
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
//setup controller B
if([segue.identifier isEqualTo:@"controllerB"]){
ControllerB *b = segue.destinationViewController;
b.delegate = self; //note this is the back reference
}
//implement controller c here if needed
}
Now move on to controllerB you need to set a property called "delegate" to hold the back reference and you need to import the header file from the root controller
现在转到 controllerB,您需要设置一个名为“delegate”的属性来保留反向引用,并且您需要从根控制器导入头文件
#import "controllerA"
@property (nonatomic,weak) controllerA *delegate;
then just before you pop back to controllerA, you set the flag
然后就在你弹回控制器A之前,你设置了标志
self.delegate.jumpNeeded = YES;
[self.navigationController popViewControllerAnimated:YES];
and that is about it. You don't have to do anything with controllerC. There are a few other ways to do, but this is pretty straight forward for your needs. hope it works out for you.
就是这样。您不必对 controllerC 做任何事情。还有其他一些方法可以做到,但这对于您的需求来说非常简单。希望它对你有帮助。
回答by Dave DeLong
If I understand you correctly, you have a stack of view controllers:
如果我理解正确的话,你有一堆视图控制器:
A (root) - B - C - D - E
And you want it to become:
你希望它变成:
A (root) - F
Right? In that case:
对?在这种情况下:
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];
// preserve the root view controller
[newViewControllers addObject:[viewControllers objectAtIndex:0]];
// add the new view controller
[newViewControllers addObject:viewThreadController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];
Swift 4
斯威夫特 4
// get current view controllers in stack and replace them
let viewControllers = self.navigationController!.viewControllers
let newViewControllers = NSMutableArray()
// preserve the root view controller
newViewControllers.add(viewControllers[0])
// add the new view controller
newViewControllers.add(viewThreadController)
// animatedly change the navigation stack
self.navigationController?.setViewControllers(newViewControllers as! [UIViewController], animated: true)
回答by M.C.
I think[self.navigationController pushViewController:viewThreadController animated:YES];
is using a different NavigationController than the statement before that.
Because after popping to the root view Controller you loose the navigation Controller you are in. Solve that using this code instead
我认为[self.navigationController pushViewController:viewThreadController animated:YES];
使用的是与之前的语句不同的 NavigationController。因为在弹出到根视图 Controller 后,您会丢失您所在的导航控制器。请改用此代码解决该问题
UINavigationController *nav = self.navigationController;
[self.navigationController popToRootViewControllerAnimated:NO];
[nav pushViewController:viewThreadController animated:YES];
I also think that this wont solve your whole problem. You will probably get an error saying that two fast popping and pushing may invalidate the NavigationController.
And to solve that you can either push the NavigationController in the viewDidDissappear Method of the 2nd View Controller or push it in the viewDidAppear Method in the Main View Controller(item listing).
我也认为这不会解决你的整个问题。您可能会收到一条错误消息,指出两次快速弹出和推送可能会使 NavigationController 失效。
为了解决这个问题,您可以在第二个视图控制器的 viewDidDissappear 方法中推送 NavigationController 或在主视图控制器(项目列表)的 viewDidAppear 方法中推送它。
回答by jlichti
Sharing a category on UINavigationController based on Dave DeLong's answer that we use in our application to keep the back button always working as required.
根据 Dave DeLong 的回答在 UINavigationController 上共享一个类别,我们在我们的应用程序中使用该答案使后退按钮始终按需要工作。
@implementation UINavigationController (PushNewAndClearNavigationStackToParent)
- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated
{
????NSArray *viewControllers = self.viewControllers;
????NSMutableArray *newViewControllers = [NSMutableArray array];
????
????// preserve the root view controller
????[newViewControllers addObject:[viewControllers firstObject]];
????// add the new view controller
????[newViewControllers addObject:newCont];
????// animatedly change the navigation stack
????[self setViewControllers:newViewControllers animated:animated];
}
@end
回答by user5018497
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];
// preserve the root view controller
for(int i = 0; i < [viewControllers count];i++){
if(i != [viewControllers count]-1)
[newViewControllers addObject:[viewControllers objectAtIndex:i]];
}
// add the new view controller
[newViewControllers addObject:conversationViewController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];
回答by Rutger Huijsmans
I used Dave's answer as inspiration and made this for Swift:
我使用 Dave 的回答作为灵感,并为 Swift 做了这个:
let newViewControllers = NSMutableArray()
newViewControllers.addObject(HomeViewController())
newViewControllers.addObject(GroupViewController())
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController>
self.navigationController?.setViewControllers(swiftArray, animated: true)
- Replace HomeViewController() with whatever you want your bottom view controller to be
- Replace GroupViewController() with whatever you want your top view controller to be
- 将 HomeViewController() 替换为您想要的底部视图控制器
- 将 GroupViewController() 替换为您想要的顶视图控制器
回答by user2387149
If what you want to do is navigate in any way inside the same navigation controller... you can access the navigationStack A.K.A. viewControllers and then set the viewcontrollers in the order that you want, or add or remove some... This is the cleanest and native way to do it.
如果你想做的是在同一个导航控制器中以任何方式导航......你可以访问 navigationStack AKA viewControllers 然后按照你想要的顺序设置视图控制器,或者添加或删除一些......这是最干净的和原生的方式来做到这一点。
UINavigationController* theNav = viewControllerToDismiss.navigationController;
UIViewController* theNewController = [UIViewController new];
UIViewController* rootView = theNav.viewControllers[0];
[theNav setViewControllers:@[
rootView,
theNewController
] animated:YES];
do any necessary validations so you don't get any exception.
做任何必要的验证,这样你就不会得到任何例外。
回答by polyclick
I don't think this is possible because popping back will deallocate everything.
我认为这是不可能的,因为弹回会释放所有内容。
I think a better way is to put your data on a model singleton class, pop to the rootviewcontroller and listen for the pop to end. Then you check if there is some data stored on the model so that you know if you should push a new viewcontroller.
我认为更好的方法是将您的数据放在模型单例类上,弹出到 rootviewcontroller 并收听弹出结束。然后您检查模型上是否存储了一些数据,以便您知道是否应该推送新的视图控制器。