如何使用 UISplitViewController 作为模态视图控制器?

发布于 2024-10-12 20:20:11 字数 236 浏览 8 评论 0原文

我正在尝试显示 UISplitViewController,将其呈现为我的 iPad 应用程序中的模态视图控制器。我设法让它显示出来,但由于某种原因,模态视图左侧有一个间隙,其大小相当于状态栏的大小,当方向更改时也会保留该间隙。

alt text

有谁知道为什么会发生这种情况?或者这是否可能?也许我只是给自己挖了一个大坑。

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.

alt text

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

泪冰清 2024-10-19 20:20:11

和你们中的许多人一样,我需要一种“模态方式”来使用 UISplitViewController。这似乎是一个老问题,但我在 StackOverflow 中发现的最多只是解释为什么当您尝试这样做时会出现问题(如上面接受的答案)或“hack-arounds”。

但是,有时更改大部分代码库并将 UISplitViewController 作为初始对象只是为了启动并运行其功能也不是很方便。

事实证明,有一种方法可以让每个人都满意(包括苹果指南)。我发现最好的解决方案是正常使用 UISplitViewController,但当需要显示/关闭时,请使用以下方法:

-(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();
 }

其中“window”是 UISplitViewController 子类的属性。系统会处理剩下的事情!

为了方便/参考,我将其作为 UISplitViewController 子类上传到 gitHub:

ModalSplitViewController

- -如何使用的示例 -

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

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

    // when done:

    [mySplitViewController dismissViewControllerWithCompletion:nil];
    mySplitViewController = nil;

旁注:我想大部分的混乱源于这样一个事实:
Apple 文档中的 UISplitView 使用示例使用窗口
在 appDelegate 中创建,并且事实上大多数人都不是
如此熟悉窗口概念 - 因为我们通常不需要
(它们在故事板或样板代码中创建一次)。

此外,如果您正在进行状态恢复,则不应
忘记以编程方式创建的 UIViewControllers 不会
系统会自动恢复。

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.

追风人 2024-10-19 20:20:11

Stock UISplitViewController 被设计为仅用作根视图控制器。以模态方式呈现违反了 Apple 人机界面指南,并且很有可能被应用程序审核团队拒绝。此外,您可能会收到以下错误:

应用程序尝试以模态方式呈现分割视图控制器

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

梦里泪两行 2024-10-19 20:20:11

从技术上讲,这就是我所做的:

1/子类化 UIViewController 即。 @interface aVC: UIViewController

2/ 在viewDidLoad中,设置一个splitViewController,即。 aSplitVC

3/ 然后 self.view = aSplitVC.view

毕竟,将 aVC 呈现为 modalViewController

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

拔了角的鹿 2024-10-19 20:20:11

我同意 Evan 的观点,即这对于 Apple 来说有点不合时宜,但我能够通过以下解决方案完成此工作版本:

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];

这使我能够在新的 UISplitViewController 中拥有一个工作后退按钮,该按钮以模态方式呈现在屏幕上。

您会注意到,我实际上传递了 VC2(UISplitViewController 的委托)其父 UINavigationController。这是我发现可以从 VC2 中关闭 UISplitViewController 的最佳方法:

[splitParentViewController dismissViewControllerAnimated:YES completion:nil];

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];
瞎闹 2024-10-19 20:20:11

我相信可以采取另一种方式:可以将拆分控制器设置为情节提要中的根窗口控制器,而不是呈现拆分控制器的自定义控制器,并且可以在其视图的顶部添加自定义控制器(即登录屏幕) )并在需要时将其从屏幕上删除(例如removeFromSuperview)。

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.

记忆で 2024-10-19 20:20:11

这个答案实际上并不正确,因为自 iOS8 以来它不再有效,如果您甚至需要支持 iOS7,您可以像实际模态 UIViewController 那样执行操作,它有一个作为 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)

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文