开发者

How to use a UISplitViewController as a Modal View Controller?

I am trying to display a UISplitViewController presenting it as a Modal开发者_开发百科 View Controller in my iPad app. I manage to have it display, but for some reason there is a gap to the left of the modal view the size of a Status Bar which is also preserved when the orientation is changed.

How to use a UISplitViewController as a Modal View Controller?

Does anybody know why this is happening? Or if this is even possible? Maybe I'm just digging myself a huge hole.


Like for many of you, I needed a 'modal way' to use the UISplitViewController. This seems to be an old issue, but all I found in StackOverflow was at best an explanation why the problem happens when you attempt to do so (like the accepted answer above), or 'hack-arounds'.

However, sometimes it is also not very convenient to change much of your code-base and make a UISplitViewController the initial object just to get it's functionality up and running.

In turns out, there's a way to make everybody happy (including Apple guidelines). The solution that I found best, was to use the UISplitViewController normally, but when needed to be shown/dismissed, use the following approach:

-(void)presentWithMasterViewController: (UIViewController *) thisMasterViewController
   andDetailViewController: (UIViewController *) thisDetailViewController
                        completion:(void(^)(void))completion
{
    masterViewController = thisMasterViewController;
    detailViewController = thisDetailViewController;

    [self setViewControllers:[NSArray arrayWithObjects:masterViewController, detailViewController, nil]];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

    self.window.rootViewController = self;

    [self.window makeKeyAndVisible];

    if(completion)
        completion();
    }

-(void)dismissViewControllerWithCompletion:(void (^)(void))completion
 {
     self.window = nil;
     masterViewController = nil;
     detailViewController = nil;
     if(completion)
         completion();
 }

Where "window", is a property of your UISplitViewController subclass. And the system will take care of the rest!

For convenience/reference, I uploaded this as a UISplitViewController subclass to gitHub:

ModalSplitViewController

--EXAMPLE ON HOW TO USE --

    mySplitViewController = [[ModalSplitViewController alloc] init];
    mySplitViewController.delegate = self;

    [mySplitViewController presentWithMasterViewController:masterViewController andDetailViewController:detailViewController completion:nil];

    // when done:

    [mySplitViewController dismissViewControllerWithCompletion:nil];
    mySplitViewController = nil;

Side-note: I guess most of the confusion originates from the fact that the UISplitView usage example from Apple documentation uses the window created in the appDelegate, and for the fact that most people are not so familiar with the window concept - because we normally don't need to (they are created once in StoryBoards or boilerplate code).

Additionally, if you are doing state restoration, one should not forget that programmatically-created UIViewControllers won't automatically be restored by the system.


The stock UISplitViewController was designed for use as the root view controller only. Presenting one modally goes against the Apple Human Interface Guidelines and has a high probability of getting rejected by the App Review Team. In addition, you may receive the error:

Application tried to present Split View Controllers modally


Technically, this is what I did:

1/ Subclass a UIViewController ie. @interface aVC: UIViewController

2/ In the viewDidLoad, set up a splitViewController, ie. aSplitVC

3/ Then self.view = aSplitVC.view

After all, present aVC as modalViewController


I agree with Evan that this is slightly off-color for Apple, but I was able to complete a working version of this with the following solution:

UISplitViewController *splitVC = [[UISplitViewController alloc] init];
    splitVC.delegate = VC2;
    splitVC.viewControllers = [NSArray arrayWithObjects:navcon1, navcon2, nil];

    UINavigationController *splitNavCon = [[UINavigationController alloc] init];
    splitNavCon.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    [splitNavCon.view addSubview:splitVC.view];
    VC2.splitParentViewController = splitNavCon;

    [self presentViewController:splitNavCon animated:YES completion:nil];

This allowed me to have a working back button in the new UISplitViewController that was presented modally on the screen.

You'll notice that I actually pass the VC2 (the delegate of the UISplitViewController) its parent UINavigationController. This was the best way that I found I could dismiss the UISplitViewController from within the VC2:

[splitParentViewController dismissViewControllerAnimated:YES completion:nil];


I believe one can do the other way around: instead of custom controller presenting split controller, one can set up the split controller as the root window controller in storyboard, and on top of its view you can add your custom controller (ie, login screen) and remove it from the screen (removeFromSuperview for example) when it is needed.


That answer is not actually correct, because it not valid any longer since iOS8 and if you need to support even iOS7 you can do that like you put actually modally UIViewController which has a container as SplitView.

let mdSplitView = self.storyboard?.instantiateViewControllerWithIdentifier("myDataSplitView") as! MyData_SplitVC
    self.addChildViewController(mdSplitView)

    mdSplitView.view.bounds = self.view.bounds
    self.view.addSubview(mdSplitView.view)
    mdSplitView.didMoveToParentViewController(self)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜