【问题标题】:How to pop back to root view controller but then push to a different view?如何弹回根视图控制器,然后推送到不同的视图?
【发布时间】:2012-08-02 23:46:11
【问题描述】:

我正在编写一个具有 3 个视图控制器的简单应用程序。根视图控制器是一个item listing,基本表视图。在这个视图控制器之外,我基于一些用户交互推送了两个不同的视图控制器 - create item 视图控制器或 view item 视图控制器。

所以,情节提要的转场看起来就像一个 V 或其他东西。

在我的create item 视图控制器上,我希望它在用户创建新项目时弹回根视图控制器,然后推送到view item 控制器,以便我可以查看新创建的项目.

我似乎无法让它工作。弹回根视图控制器很容易,但我无法推送 view item 控制器。

有什么想法吗?我在下面粘贴了我的代码。 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];

                                          }];

}

【问题讨论】:

  • 我不会为“创建项目”和“查看项目”创建不同的视图控制器。确实,您可能希望在创建项目后查看它,但总有另一种可能性,您的用户可能希望在查看项目后对其进行编辑。设计一个视图控制器来允许在一个视图中创建、查看和编辑会更容易。大多数应用程序都是这样设计的。节省您的时间。

标签: ios xcode cocoa uiviewcontroller uinavigationcontroller


【解决方案1】:

如果我理解正确的话,你有一堆视图控制器:

A (root) - B - C - D - E

你希望它变成:

A (root) - F

对吗?在这种情况下:

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];

斯威夫特 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)

【讨论】:

  • 这将动画从视图 E 到视图 F。
  • ^ @LysannSchlegel 这就是重点。它的动画从 E->F 开始,但是如果你点击后退按钮,你将转到 A 而不是 E。基本上,将后退堆栈清除到父视图,中间没有任何时髦/意外的动画!
  • Dave 的回答很棒,通过 UINavigationController 上的 Category 将其提升到重用级别:stackoverflow.com/a/25771209/1103584
  • 谁能用 Swift 做这个?
  • 只是一个警告,当您按下返回按钮时,这会产生不必要的屏幕闪烁。虽然它在技术上确实有效,但如果你想润色,这不适合你。
【解决方案2】:

我认为
[self.navigationController pushViewController:viewThreadController animated:YES]; 正在使用与之前的语句不同的 NavigationController。 因为在弹出到根视图控制器后,你会失去你所在的导航控制器。改用这段代码解决这个问题

UINavigationController *nav = self.navigationController; 
[self.navigationController popToRootViewControllerAnimated:NO];
[nav pushViewController:viewThreadController animated:YES];

我也认为这不会解决你的整个问题。您可能会收到一条错误消息,说两次快速弹出和推送可能会使 NavigationController 无效。
为了解决这个问题,您可以将 NavigationController 推送到第二个视图控制器的 viewDidDissappear 方法中,也可以将其推送到主视图控制器的 viewDidAppear 方法中(项目列表)。

【讨论】:

  • 我的经验:使用动画:YES 时,它不会按预期工作,但动画:NO 可以完成工作。而且由于 popToRoot 更短,所以我使用了它。希望对您有所帮助!
  • 我相信只需使用 popToRootController 就是答案。无需对 viewController 堆栈做任何有趣的事情,推送可以照常进行。
【解决方案3】:

完成您想要做的事情的一种简单方法是在您的主根视图控制器中构建一些简单的逻辑 -(void)viewWillAppear 方法,并使用委托回调来翻转逻辑开关。基本上是对根控制器的“反向引用”。这是一个简单的例子。

主根控制器(考虑这个控制器a) - 称之为controllerA 设置一个属性来跟踪跳转状态

@property (nonatomic) BOOL jumpNeeded;

中设置一些逻辑
- (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];
    }   
}

现在,在主根控制器中,选择TableView行时,请执行此操作 在您的 tableView 中推送到 controllerB 时确实选择了方法

[self performSegueWithIdentifer@"controllerB" sender:self];

然后实现你的准备 segue 方法

- (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
}

现在转到控制器 B 您需要设置一个名为“delegate”的属性来保存反向引用 并且需要从根控制器导入头文件

#import "controllerA"

@property (nonatomic,weak) controllerA *delegate;

然后在您弹回控制器A之前,设置标志

   self.delegate.jumpNeeded = YES;
    [self.navigationController popViewControllerAnimated:YES];

就是这样。您不必对控制器C 做任何事情。还有其他一些方法可以做,但这对于您的需求来说非常简单。希望它对你有用。

【讨论】:

  • 我选择了这个作为答案,因为代表是我最终要走的路线。不过,我完全放弃了 push segue 并使用了模态 segue,以获取 create item 视图。
  • 我很高兴这些提示让您朝着适合您的方向前进。祝你好运!
【解决方案4】:

根据我们在应用程序中使用的 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

【讨论】:

    【解决方案5】:
    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];
    

    【讨论】:

    • 能否请您详细说明您的答案,添加更多关于您提供的解决方案的描述?
    【解决方案6】:

    我认为这是不可能的,因为弹回会释放所有内容。

    我认为更好的方法是将您的数据放在模型单例类中,弹出到 rootviewcontroller 并监听弹出结束。然后检查模型上是否存储了一些数据,以便知道是否应该推送新的视图控制器。

    【讨论】:

      【解决方案7】:

      我以 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)
      
      1. 用你想要的底视图控制器替换 HomeViewController()
      2. 将 GroupViewController() 替换为您想要的顶视图控制器

      【讨论】:

        【解决方案8】:

        如果您想做的是在同一个导航控制器中以任何方式导航...您可以访问 navigationStack A.K.A. viewControllers 然后按您想要的顺序设置 viewcontrollers,或者添加或删除一些... 这是最干净、最原生的方式。

                UINavigationController* theNav = viewControllerToDismiss.navigationController;
                UIViewController* theNewController = [UIViewController new];
                UIViewController* rootView = theNav.viewControllers[0];
                [theNav setViewControllers:@[
                                             rootView,
                                             theNewController
                                             ] animated:YES];
        

        进行任何必要的验证,以免出现任何异常。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-06-26
          • 1970-01-01
          • 2010-12-11
          • 2012-07-07
          • 2014-10-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多