Как использовать 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:
- ПРИМЕР, КАК ИСПОЛЬЗОВАТЬ -
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)