在动画之前修改UINavigationController viewControllers堆栈

时间:2014-10-14 15:32:06

标签: ios ios7 uiviewcontroller ios8

我有一个应用程序,您可以在不同程度上自定义产品。在某些情况下,选项被拆分为两个视图,而在其他一些情况下,第一步不是必需的。

我想要的是将所有产品视为相同并将第一个自定义步骤视图控制器推送到导航控制器堆栈,让视图控制器决定是否需要执行此步骤。如果必要,我希望它将一些默认选项应用于产品并立即跳过(在转换动画之前)到第2步,同时不允许用户备份到第一步。

在第2步时,正常UINavigationController.viewControllers堆栈可能如下所示:

[ListView (root)] -> [CustomizeStep1] -> [CustomizeStep2]

Normal application flow

但我希望它将默认值应用于产品并修改视图控制器堆栈,以便:

[ListView (root)] -> [CustomizeStep1]
        ----- becomes -----
[ListView (root)] -> [CustomizeStep2]

我尝试过在CustomizeStep1视图控制器中使用这样的代码:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (shouldSkipToStep2) {
        UINavigationController *navController = self.navigationController;

        // Move directly to step 2
        UIStoryboard *storyboardLoader = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *customizeStep2VC = [storyboardLoader instantiateViewControllerWithIdentifier:@"customizeStep2"];

        // Replace current view contoller
        NSMutableArray *viewHierarchy = [NSMutableArray arrayWithArray:navController.viewControllers];
        [viewHierarchy removeObject:self];
        [viewHierarchy addObject:customizeVC];

        // Apply new viewController stack
        [navController setViewControllers:viewHierarchy animated:NO];
    }
}

如果我在设置导航控制器的viewControllers数组之后看一下,所有内容都按预期显示。

iOS 7中会发生什么

执行此操作时,UINavigationController的整个功能会中断。 CustomizeStep1视图控制器仍然可以动画但不起作用。点击后退按钮仍会显示CustomizeStep1。尝试与视图控制器交互会导致应用程序崩溃。 (但是,如果在没有滑动过渡的情况下显示视图控制器,它将按预期工作。)

iOS 7 example

iOS 8中会发生什么

CustomizeStep1视图控制器仍处于动画状态,但在转换结束后立即切换到显示CustomizeStep2。除此之外,它按预期工作。

iOS 8 example


所以,我的问题是,是否有更好的地方添加代码来修改导航控制器上的视图控制器堆栈?

我显然需要等到视图控制器添加到导航控制器,否则我无法替换堆栈中的视图控制器。但是,我需要能够取消过渡动画,以便我可以在CustomizeStep2中设置动画。

我很感激,如果这是不可能的,只是想检查是否有人知道这方面的好方法。


编辑:

我希望理想情况出现在用户

enter image description here

1 个答案:

答案 0 :(得分:0)

使用动画完成后调用的viewWillAppear:而不是viewDidAppear:

您的视图控制器上可能有一个布尔值,表示它是否已填充:

@interface ViewControllerOne : UIViewController

@property (nonatomic, assign, getter = isInitiallyFilledIn) BOOL initiallyFilledIn;

@end

然后,当它最初填充时,只表示这个布尔值。

ViewControllerOne *viewController = [[ViewControllerOne alloc] init];
[viewController setInitiallyFilledIn:YES];

现在,在viewDidAppear:中,检查此布尔值并检查之前是否已启动该方法。如果之前没有启动(允许编辑)并且最初填写它,请按下一个控制器!

@interface ViewControllerOne

@property (nonatomic, assign) BOOL hasCheckedFillInStatusBefore;

@end

@implementation ViewControllerOne

-(void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    if ([self isInitiallyFilledIn] && ![self hasCheckedFillInStatusBefore]) {

        // push the next view controller

    }
    [self setHasCheckedFillInStatusBefore:YES];

}

@end

或者,如果要同时显示两个视图控制器,可以更改导航堆栈:

// create instances of ViewControllerOne and ViewControllerTwo

NSMutableArray *viewControllers = [[[self navigationController] viewControllers] mutableCopy];
[viewControllers addObjectsFromArray:@[viewControllerOne, viewControllerTwo]];
[[self navigationController] setViewControllers:viewControllers animated:YES];

注意,如果您在该方法中进行任何设置(例如后退按钮标题或视图控制器标题),则ViewControllerOne将不会调用viewDidLoad,您将不得不手动调用设置视图控制器之前的方法或将该设置移动到初始化程序。