Как использовать UISplitViewController в качестве модального контроллера представления?

Я пытаюсь отобразить UISplitViewController, представляя его в качестве модального View Controller в моем приложении для iPad. Мне удается его отобразить, но по какой-то причине слева от модального окна есть промежуток размера строки состояния, который также сохраняется при изменении ориентации.

альтернативный текст

Кто-нибудь знает, почему это происходит? Или если это вообще возможно? Может быть, я просто копаю себе огромную яму.

6 ответов

Решение

Акции UISplitViewController был разработан для использования только в качестве контроллера корневого представления. Представление одного из них идет вразрез с руководящими принципами Apple Human Interface Guidelines и с большой вероятностью будет отклонено группой проверки приложений. Кроме того, вы можете получить сообщение об ошибке:

Приложение попыталось представить Split View Controllers модально

Как и многим из вас, мне нужен был "модальный способ" использовать UISplitViewController. Кажется, это старая проблема, но все, что я нашел в Stackru, в лучшем случае объясняло, почему проблема возникает, когда вы пытаетесь это сделать (например, принятый ответ выше) или "обходные пути".

Однако иногда также не очень удобно менять основную часть кода и делать UISplitViewController начальным объектом просто для того, чтобы его функциональность была запущена и работала.

Оказывается, есть способ сделать всех счастливыми (включая рекомендации Apple). Решение, которое я нашел наилучшим, состояло в том, чтобы использовать 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();
 }

Где "окно", это свойство вашего подкласса 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;

Примечание: я полагаю, что большая часть путаницы происходит из-за того факта, что пример использования UISplitView из документации Apple использует окно, созданное в appDelegate, и из-за того, что большинство людей не очень знакомы с концепцией окна - потому что мы обычно не понимаем в этом нет необходимости (они создаются один раз в StoryBoards или шаблонном коде).

Кроме того, если вы выполняете восстановление состояния, не следует забывать, что программно созданные UIViewControllers не будут автоматически восстановлены системой.

Технически, это то, что я сделал:

1 / Подкласс UIViewController т.е. @interface aVC: UIViewController

2 / В viewDidLoad установите splitViewController, т.е. aSplitVC

3 / Тогда self.view = aSplitVC.view

В конце концов, представьте aVC как modalViewController

Я согласен с Эваном в том, что для 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. Это был лучший способ, с помощью которого я обнаружил, что могу удалить UISplitViewController из VC2:

[splitParentViewController dismissViewControllerAnimated:YES completion:nil];

Я полагаю, что можно поступить наоборот: вместо настраиваемого контроллера, представляющего контроллер разбиения, можно настроить контроллер разделения в качестве корневого контроллера окна в раскадровке, а поверх его представления вы можете добавить свой настраиваемый контроллер (т. Е. Экран входа в систему).) и удалите его с экрана (например, removeFromSuperview), когда это необходимо.

Этот ответ на самом деле не является правильным, потому что он недействителен больше, чем 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)
Другие вопросы по тегам