iOS: Best practices for a “one-way” navigation con

2019-01-28 20:31发布

问题:

I'm developing an app which is essentially a sequence of many different tests (for simplicity, think about an SAT test or a Mensa test). Each test is implemented in a different View+View Controller.

Initially I wanted to use Storyboards and UINavigationControllers for managing the sequence of the tests and the transitions between them, but now I'm questioning the validity of this approach. A UINavigationController is a stack while my navigation is one-way only (once you've completed a test you can't go back). Is there a better way to implement the app? Can I still leverage Storyboards somehow?

回答1:

I'd use a custom container view controller. So to your main scene, add a "container view". If your target is iOS6, then when editing your storyboard there is a special "container view" object that you can now drag onto your custom container view controller's scene:

If iOS 5, then (a) you have to create the first child scene manually; (b) give it a unique storyboard id (in my example, InitialChild, and (c) you manually instantiate that first child controller and add it as a child programmatically. Thus, assuming you have a UIView called containerView in your custom container view controller's scene, you can have a method like:

- (void)addInitialChild
{
    UIViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:@"InitialChild"];

    [self addChildViewController:child];
    child.view.frame = self.containerView.bounds;
    [self.containerView addSubview:child.view];
    [child didMoveToParentViewController:self];
}

When you want to transition to the next scene, subclass your own UIStoryboardSegue:

In ReplaceSegue.h:

@interface ReplaceSegue : UIStoryboardSegue

@end

In ReplaceSegue.m

@implementation ReplaceSegue

- (void)perform
{
    UIViewController *source = self.sourceViewController;
    UIViewController *destination = self.destinationViewController;
    UIViewController *container = source.parentViewController;

    [container addChildViewController:destination];
    destination.view.frame = source.view.frame;
    [source willMoveToParentViewController:nil];

    [container transitionFromViewController:source
                           toViewController:destination
                                   duration:0.5
                                    options:UIViewAnimationOptionTransitionCrossDissolve
                                 animations:^{
                                 }
                                 completion:^(BOOL finished) {
                                     [source removeFromParentViewController];
                                     [destination didMoveToParentViewController:container];
                                 }];
}
@end

Then, when doing a segue from the first contained scene to the next, specify a "custom" segue, and use this "ReplaceSegue" as the class (just click on the segue to select it and then look at the "Attributes inspector").

The resulting storyboard might look like (note the "{}" designation between the various children):


References:

  • For general discussion of containment, see Implementing a View Container Controller in the UIViewController Class Reference.

  • For some details about the implementation, see Creating Custom Container View Controllers in the View Controller Programming Guide for iOS.



回答2:

Then just load the next view controller and replace current view (in some top-level view or in app window) with the new one. Add animations if you want. What's the problem?



回答3:

You can also use view animation to avoid push viewcontrollers.you can give view animation like pushing a VC