【问题标题】:Amending UINavigationController viewControllers stack before animation在动画前修改 UINavigationController viewControllers 堆栈
【发布时间】:2014-12-09 11:23:09
【问题描述】:

我有一个应用程序,您可以在其中对产品进行不同程度的定制。在某些情况下,选项会分成两个视图,而在其他情况下,不需要第一步。

我希望对所有产品一视同仁,并将第一个自定义步骤视图控制器推送到导航控制器堆栈,让该视图控制器决定是否需要此步骤。如果不需要,我希望它对产品应用一些默认选项并立即(在过渡动画之前)跳到第 2 步,同时不允许用户返回到第 2 步。

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

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

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

[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 8 中发生了什么

CustomizeStep1 视图控制器仍然在动画中,但在过渡结束后它立即捕捉到显示CustomizeStep2。除此之外,它按预期工作。


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

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

如果这是不可能的,我很感激,只是想检查一下是否有人知道解决这个问题的好方法。


编辑:

我希望它如何理想地向用户显示

【问题讨论】:

    标签: ios ios7 uiviewcontroller ios8


    【解决方案1】:

    使用动画结束后调用的viewDidAppear:,而不是viewWillAppear:

    你可以在你的视图控制器上有一个布尔值来表示它是否被填充:

    @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,因此如果您在该方法中进行任何设置(例如后退按钮标题或视图控制器标题),您必须在设置之前手动调用该方法视图控制器或将该设置移至初始化程序。

    【讨论】:

    • 哦,根据你给出的动画,我可能误解了这个问题,你想同时推送两个视图控制器而不是一个接一个?如果是这样,我可以编辑这个答案。
    • 是的,没关系,这可能就是我需要玩这个的方式。但是理想情况下,我想取消过渡动画并在屏幕上显示step 1 之前切换到step 2...即,在导航控制器的视图控制器堆栈开始在step 1 中进行动画处理之前修改它。
    • 好的 - 我更新了我的答案,应该可以让你同时推送两个。
    • 我在原始问题中添加了一个新动画来说明理想的功能。基本上,用户根本不应该注意到CustomizeStep1 参与其中。我希望CustomizeStep1 成为决定是否显示的班级......
    • 您是否可以在StepOneViewController 中添加一个类或实例方法来决定,然后在主视图控制器中使用该方法来决定是推动第一步还是只进入第二步?推一个,然后让它改变堆栈,不管你用什么方法,都会有很多问题。
    猜你喜欢
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多