如何通过多个视图展开而不显示中间视图

假设我们有三个视图控制器:1,2和3.使用故事板,从视图控制器3放松到使用放松轮廓来查看控制器1是相当简单的。 但是,放卷时,视图控制器2在视图控制器1显示之前短暂可见。 有没有办法从3到1而不显示2?

视图控制器1:

- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"one did appear"); } - (IBAction)goToTwo:(id)sender { NSLog(@"#### segue to two"); [self performSegueWithIdentifier:@"TwoSegue" sender:self]; } - (IBAction)unwindToOne:(UIStoryboardSegue *)sender { } 

视图控制器2:

 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"two did appear"); } - (IBAction)goToThree:(id)sender { NSLog(@"#### segue to three"); [self performSegueWithIdentifier:@"ThreeSegue" sender:self]; } 

视图控制器3:

 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"three did appear"); } - (IBAction)unwindToOne:(id)sender { NSLog(@"#### unwind to one"); [self performSegueWithIdentifier:@"OneSegue" sender:self]; } 

这会产生以下日志消息:

  • 一个确实出现了
  • 延续到二
  • 两个确实出现
  • 延续到三
  • 三个确实出现了
  • 放松一下
  • 两个确实出现
  • 一个确实出现了

我试过使用自定义赛格和禁用animation。 虽然删除animation使视图控制器2出现一个更短的时间,它仍然会出现。 有什么办法来编程这个行为?

故事板的屏幕截图:

在这里输入图像说明

这似乎是由于展开赛段search最近的视图控制器的方式,该视图控制器实现了您在故事板中指定的展开操作。 从文档 :

如何解决Segueselect目的地

当展开的顺序被触发时,它必须定位最接近的视图控制器,该视图控制器实现了在定义展开顺序时指定的展开操作。 此视图控制器成为展开顺序的目的地。 如果没有find合适的视图控制器,放开的继续被中止。 search顺序如下:

viewControllerForUnwindSegueAction:fromViewController:withSender:消息被发送到源视图控制器的父级。

viewControllerForUnwindSegueAction:fromViewController:withSender: message被发送到下一个父视图控制器[…]

您可以重写canPerformUnwindSegueAction:fromViewController:withSender:如果您对视图控制器是否应处理展开操作有特定的要求。

在你的例子中的视图控制器没有父,所以看起来 fallback(我看不到文档)是实例化每个canPerformUnwindSegueAction并依次调用canPerformUnwindSegueAction 。 在ViewControllerTwo中从这个方法返回NO并不妨碍它的实例化和显示,所以不能解决问题。

我试过你的代码embedded导航控制器,它工作正常。 这是因为在这种情况下, UINavigationController是每个视图控制器的父级,它处理目标视图控制器的所有select。 更多文档:

容器视图控制器

容器视图控制器在展开过程中有两个职责,下面将对此进行讨论。 如果使用SDK提供的容器视图控制器(如UINavigationController),则会自动处理这些控制器。

如果您要创build一个简单的容器视图控制器作为您的三个视图控制器的父级,则可以使用其viewControllerForUnwindSegueAction方法在调用该控制器上的canPerformUnwindSegueAction之前检查其每个子控制器是否存在展开操作,以及最后返回第一个返回YES的那个。

select一个子视图控制器来处理放松操作

正如Unwind Segueselect其目的地的方式中所述,unwind segue的源视图控制器将根据它的父级来定位要处理展开操作的视图控制器。 您的容器视图控制器应该覆盖清单2中所示的方法,以便在其子视图控制器中search想要处理展开操作的视图控制器。 如果一个容器的子视图控制器都不想处理展开动作,它应该调用超级实现并返回结果。

容器视图控制器应该以对该容器有意义的方式search其子项。 例如,UINavigationController通过其viewControllers数组向后search,从导航堆栈顶部的视图开始。

清单2重写此方法以返回想要处理展开操作的视图控制器。 – (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender

容器视图控制器的devise有一个苹果专用的整篇文章 ,我不会在这里复制(已经有足够多的苹果在这个答案中的写作!),但它看起来需要一些考虑才能得到它的权利,因为它取决于你想要在你的应用程序中扮演的确切angular色。

一个快速的解决方法,使用unwind segues来获得所需的行为,可以将视图控制器embedded到UINavigationController ,然后隐藏导航栏

 [self.navigationController setNavigationBarHidden:YES]; 

乔希的回答让我find了一个解决scheme。 这是如何完成这个:

创build一个根UINavigationController,并将其分配给扩展UINavigationController并覆盖segueForUnwindingToViewController:fromViewController:标识方法的类。 如果需要,这可以通过标识符进行过滤。

CustomNavigationController:

 - (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier { return [[CustomUnwindSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; } 

创build一个自定义的push segue,其行为像一个模态赛格,但利用我们的导航控制器。 使用这个所有的“推”阶段。

CustomPushSegue:

 -(void) perform{ [[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:NO]; } 

创build一个自定义的展开顺序,使用导航控制器popup到目的地。 这是由我们的导航控制器在segueForUnwindingToViewController:fromViewController:标识符方法调用。

CustomUnwindSegue:

 - (void)perform { [[self.destinationViewController navigationController] popToViewController:self.destinationViewController animated:NO]; } 

通过使用这些模式的组合,第二个视图控制器在退绕过程中不会出现。

新的日志输出:

  • 一个确实出现了
  • ####继续两个
  • 两个确实出现
  • ####继续三
  • 三个确实出现了
  • ####放松到一个
  • 一个确实出现了

我希望这可以帮助有同样问题的其他人。

看起来像习惯性的塞格正在被使用,所以有可能干扰某种方式,虽然我从来没有见过它开心。 我build议你看看苹果的例子项目。 它也有自定义的塞格,所以它应该作为一个很好的起点。

苹果公司的解决问题的例子

我很惊讶你看到了你所看到的行为,但改变它的一种方法是使用明确的解雇而不是放松的解决scheme(假定前锋是模态的)。

如果VC1这样做,一切都会看起来不错:

 [self dismissViewControllerAnimated:YES completion:^{}]; 

或者,如果一些其他的VC做到这一点:

 [vc1 dismissViewControllerAnimated:YES completion:^{}]; 

唯一的麻烦就是你需要一个vc1的句柄,如果你想从其他vc中解雇。 你可以使用委托模式让vc1知道它应该解雇,但更简单的解决scheme是让vc2或者3在发生解除应用时发布通知。

风险投资2或3可以做到这一点:

 // whenever we want to dismiss [[NSNotificationCenter defaultCenter] postNotificationName:@"TimeToDismiss" object:self]; 

而VC1可以做到这一点:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doDismiss:) name:@"TimeToDismiss" object:nil]; - (void)doDismiss:(NSNotification *)notification { [self dismissViewControllerAnimated:YES completion:^{}]; }