Best way to switch between UISplitViewController a

2020-01-24 09:18发布

I'm authoring an iPad app. One of the screens in the app is perfectly suited to using a UISplitViewController. However, the top level of the app is a main menu, which I don't want to use a UISplitViewController for. This presents a problem, because Apple state that:

  1. UISplitViewController should be the top level view controller in the app, i.e. its view should be added as the subview of UIWindow

  2. if used, UISplitViewController should be there for the lifetime of the app -- i.e. don't remove its view from UIWindow and put another in place, or vice versa

Having read around and experimented, it seems to only viable option to satisfy Apple's requirements and our own is to use modal dialogs. So our app has a UISplitViewController at the root level (i.e. its view added as the subview of UIWindow), and to show our main menu, we push it as a full-screen modal dialog onto the UISplitViewController. Then by dismissing the main menu view controller modal dialog, we can actually show our split view.

This strategy seems to work fine. But it begs the questions:

1) Is there any better way of structuring this, without modals, that also meets all the requirements mentioned? It seems a bit odd having the main UI appear by virtue of being pushed as a modal dialog. (Modals are supposed to be for focused user tasks.)

2) Am I at risk of app store rejection because of my approach? This modal strategy is probably 'misusing' modal dialogs, as per Apple's human interface guidelines. But what other choice have they given me? Would they know that I'm doing this, anyway?

9条回答
来,给爷笑一个
2楼-- · 2020-01-24 09:39

Adding to the answer of @tadija I am in a similar situation:

My app was for phones only, and I am adding a tablet UI. I decided doing it in Swift in the same app - and eventually migrate all the app to use the same storyboard (when I feel the IPad version is stable, using it for phones should be trivial with the new classes from XCode6).

No segues were defined in my scene yet and it still works.

My the code in my app delegate is in ObjectiveC, and is slightly different - but uses the same idea. Note that I am using the default view controller from the scene, unlike previous examples. I feel this will also work on IOS7/IPhone in which the runtime will generate a regular UINavigationController instead of a UISplitViewController. I might even add new code which will push the login view controller on IPhones, instead of changing the rootVC.

- (void) setupRootViewController:(BOOL) animated {
    UIViewController *newController = nil;
    UIStoryboard *board = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
    UIViewAnimationOptions transition = UIViewAnimationOptionTransitionCrossDissolve;

    if (!loggedIn) {
        newController = [board instantiateViewControllerWithIdentifier:@"LoginViewController"];
    } else {
        newController = [board instantiateInitialViewController];
    }

    if (animated) {
        [UIView transitionWithView: self.window duration:0.5 options:transition animations:^{
            self.window.rootViewController = newController;
            NSLog(@"setup root view controller animated");
        } completion:^(BOOL finished) {
            NSLog(@"setup root view controller finished");
        }];
    } else {
        self.window.rootViewController = newController;
    }
}
查看更多
\"骚年 ilove
3楼-- · 2020-01-24 09:41

And who said you can have only one window ? :)

See if my answer on this similar question can help.

This approach is working very well for me. As long as you don't have to worry about multiple displays or state restoration, this linked code should be enough to do what you need: you don't have to make your logic look backwards or rewrite existing code, and can still take advantage of the UISplitView in a deeper level within your application - without (AFAIK) breaking Apple guidelines.

查看更多
一夜七次
4楼-- · 2020-01-24 09:45

Just ran into this problem on a project and thought I'd share my solution. In our case (for iPad), we wanted to start with a UISplitViewController with both view controllers visible (using preferredDisplayMode = .allVisible). At some point in the detail (right) hierarchy (we had a navigation controller for this side, too) we wanted to push a new view controller over the entire split view controller (not use a modal transition).

On iPhone, this behavior comes for free—as only one view controller is visible at any time. But on iPad we had to figure something else out. We ended up going with a root container view controller that adds the split view controller to it as a child view controller. This root view controller is embedded in a navigation controller. When the detail view controller in the split view controller wants to push a new controller over the entire split view controller, the root view controller pushes this new view controller with its navigation controller.

查看更多
淡お忘
5楼-- · 2020-01-24 09:46

Touche! Ran in to the same issue and solved it the same way using modals. In my case it was a login view and then the main menu as well to be shown before the splitview. I used the same strategy as thought out by you. I (as well as several other knowledgeable iOS folks I spoke to) could not find a better way out. Works fine for me. User never notices the modal anyway. Present them so. And yes I can also tell you that there are quite a few apps doing the same under the hood tricks on the App store. :) On another note, do let me know if you figure a better way out somehow someway sometime :)

查看更多
Deceive 欺骗
6楼-- · 2020-01-24 09:47

Another option: In the details view controller I display a modal view controller:

let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
if (!appDelegate.loggedIn) {
    // display the login form
    let storyboard = UIStoryboard(name: "Storyboard", bundle: nil)
    let login = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as UIViewController
    self.presentViewController(login, animated: false, completion: { () -> Void in
       // user logged in and is valid now
       self.updateDisplay()
    })
} else {
    updateDisplay()
}

Don't dismiss the login controller without setting the login flag. Note that in IPhones the master view controller will come first, so a very similar code will need to be on the master view controller.

查看更多
【Aperson】
7楼-- · 2020-01-24 09:51

I did a UISplitView as initial view, than it goes modally to a fullscreen UIView and back to UISplitView. If you need to go back to the SplitView you have to use a custom segue.

Read this link (translate it from japanese)

UIViewController to UISplitViewController

查看更多
登录 后发表回答