自定义segue将特定的UIViewController推送到UINavigationController
我想创建一个自定义的segue,它的作用方式与标准push segue在UINavigationController视图控制器上使用时的作用相同。我实现了我的自定义赛格瑞:自定义segue将特定的UIViewController推送到UINavigationController
CustomSegue.m
-(void)perform {
UIViewController *source = (UIViewController *)[self sourceViewController];
UIViewController *dest =(UIViewController *)[self destinationViewController];
if (1==2 //test) {
[source.navigationController pushViewController:dest animated:YES];
}
else {
UIViewController *altDest = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:NULL]
instantiateViewControllerWithIdentifier:@"alternateView"];
[source.navigationController pushViewController:altDest animated:YES];
}
正如你所看到的,我想用一个自定义推赛格瑞的原因是,我可以决定哪些视图控制器推基于用户配置(目前只检查一个微不足道的1 == 2表达式)。我可以在没有问题的情况下实例化替代视图控制器,但我希望能够做的事是每次都重复加载视图控制器(使用后退按钮和下一个按钮)来回移动。有没有一种方法可以从故事板中检索现有的实例,或者一些标准的方法来实现这一点?
而是其perform
定制赛格瑞的,顺便做你的描述,即选择在实时是否推dest
或altDest
,或者是(1)不使用在所有塞格斯并调用pushViewController
直接作为你在这里做,或者(2)准备从视图控制器发出的两个段落作为一个整体,并且呼叫performSegueWithIdentifier:
说我们应该执行哪一个。
至于直接从dest
要altDest
,可以对dest
顶推altDest
然后从导航控制器的视图控制器的堆叠移除dest
。
像这么多关于iOS的东西,如果你根本不使用故事板,那么这会变得更加容易和明显。这就是为什么我不喜欢故事板:他们非常简单和有限,而且他们注意力从iOS 真正的工作。
无法从故事板中检索现有的控制器 - 如果有controllerWithIdentifier:方法来执行此操作,但没有方法,那将会很不错。 Segmentation(除了unwinds)总是实例化新的控制器,所以我认为你不能用segue做你想做的事情。如果您想多次向前推(推)到同一个控制器,那么您需要通过创建一个指向您的控制器的属性并在推入该控制器之前检查该控制器是否存在来执行代码。
正如其他人指出的那样,您不能使用segue推送到控制器的现有实例。执行segue的过程总是为您创建一个新的实例作为目标控制器。我个人认为,当我在视图控制器的现有实例之间跳转时,我认为“容器视图控制器”(例如UIPageViewController
)可以很容易地在两个或多个控制器之间转换,而不必每次都重新实例化它们。
如果您不喜欢页面视图控制器强加的约束(例如,您可能不喜欢iOS 5版本仅支持页面卷曲转换,或者iOS 6只添加滚动转换,并且您想要别的东西),那么你会做一个自定义的容器视图控制器。例如,如果我想在两个视图控制器之间跳转,并且不会每次重新实例化它们,我首先会创建一个自定义容器视图控制器,即“父级”,并确保我有一个属性以跟踪哪个孩子我目前在:
@property (nonatomic) NSInteger childViewIndex;
如果支持iOS 6。只有0和以上,我会然后添加一个“容器视图”到我的父视图控制器的场景。如果以6.0之前支持IOS版本,我会一个标准UIView
添加到场景中,然后手动实例化的第一个孩子控制器:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIViewController *controller;
// add the first child
UIViewController *controller = [self addChildWithIdentifier:@"One"];
[self.containerView addSubview:controller.view];
[controller didMoveToParentViewController:self];
self.childViewIndex = 0;
}
- (UIViewController *)addChildWithIdentifier:(NSString *)storyboardIdentifier
{
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:storyboardIdentifier];
[self addChildViewController:controller];
controller.view.frame = self.containerView.bounds;
controller.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
return controller;
}
然后,当我想过渡到第二个孩子(或过渡回第一个孩子),我会打电话给父视图控制器中执行以下程序:
- (void)transitionToViewControllerIndex:(NSInteger)index
{
// don't do anything if we're trying to transition to ourselves!
if (index == self.childViewIndex)
return;
// identify the two controllers in question
UIViewController *sourceController = self.childViewControllers[self.childViewIndex];
UIViewController *destinationController;
// if we're asking for page 2, but we only have one defined, then we'll have to instantiate it
BOOL instantiateDestination = (index == 1 && [self.childViewControllers count] < 2);
if (instantiateDestination)
destinationController = [self addChildWithIdentifier:@"Two"];
else
destinationController = self.childViewControllers[index];
// configure the destination controller's frame
destinationController.view.frame = sourceController.view.frame;
// if you're jumping back and forth, set the animation appropriate for the
// direction we're going
UIViewAnimationOptions options;
if (index > self.childViewIndex)
{
options = UIViewAnimationOptionTransitionFlipFromRight;
}
else
{
options = UIViewAnimationOptionTransitionFlipFromLeft;
}
// now transition to that destination controller
[self transitionFromViewController:sourceController
toViewController:destinationController
duration:0.5
options:options
animations:^{
// for simple flip, you don't need anything here,
// but docs say this can't be NULL; if you wanted
// to do some other, custom annotation, you'd do it here
}
completion:^(BOOL finished) {
if (instantiateDestination)
[destinationController didMoveToParentViewController:self];
}];
self.childViewIndex = index;
}
因此,过渡到第二子视图控制器,你可以直接电话咨询:
[self transitionToViewControllerIndex:1];
如果你想转换回,你可以拨打:
[self transitionToViewControllerIndex:0];
我只在这里划伤表面,但容器视图控制器(或者如果没有通用的标准为你做的工作,一个自定义的容器视图控制器)正是你需要的。
欲了解更多信息,请参见:
Creating Custom Container View Controllers的视图控制器编程指南适用于iOS英寸
在WWDC 2011届影片Implementing UIViewController Containment(Apple开发者ID需要)。
Implementing a Container View Controller in UIViewController类引用。
Page View Controllers in the View Controller Catalog for iOS。
下面是如何在代码完全操作导航界面我的书的讨论:http://www.apeth.com/iOSBook/ch19.html#_configuring_a_navigation_controller – matt 2013-04-27 16:18:33
谢谢!成功管理您的工作和@ rdelmar的答案。我已经将“Next”按钮操作更改为标准IBAction,以便推送所需的视图控制器而不是使用segues - 这样,我可以将实例化视图控制器存储在堆栈中的前一个视图控制器中,并在实例化视图控制器时将其推送存在。我同意故事板掩盖了很多正在发生的事情,这导致了对低层的理解不足。我会标记你的答案,当它让我:) – 2013-04-27 16:47:54
你可能想要尝试'setViewControllers:animated:'。它可以让你重新安排现有的视图控制器*和*可能添加更多的视图控制器,删除现有的视图控制器等,*和*它执行自动动画(除非你不告诉它)。因此,您可以将两个备用视图控制器保留在堆栈中,并重新排列它们。 – matt 2013-04-27 16:56:44