UISplitViewController: Как заставить показать главное всплывающее окно при запуске приложения? (портрет)

В приложении для iPad я использую UISplitViewController. Мне нужно заставить показывать главное всплывающее окно при запуске приложения в портретном режиме.

Сейчас я использую этот код, и он хорошо работает на iOS 5.0.

if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
   if ([[[AppDelegate sharedAppDelegate] splitViewController] respondsToSelector:[[[AppDelegate sharedAppDelegate] btnMenu] action]]) {
      [[[AppDelegate sharedAppDelegate] splitViewController] performSelector:[[[AppDelegate sharedAppDelegate] btnMenu] action]];
   }            
}

Но в iOS 5.1 (с новым типом главного всплывающего окна) поведение кажется случайным. Иногда всплывающее окно отображается в полноэкранном режиме, а иногда работает хорошо.

Какие-то предложения по 5.1?


person alejandromp    schedule 03.05.2012    source источник
comment
Вот хороший ответ: stackoverflow.com/a/15817100/733862   -  person akofink    schedule 26.04.2013


Ответы (8)


Некоторое время я боролся с этим, и даже сейчас я не на 100% доволен решением, но это единственное, что я смог придумать, учитывая текущие ограничения.

Сначала переопределите следующий метод делегата:

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController

и используйте его, чтобы получить ссылку на элемент кнопки панели и сохранить ее в iVar:

barButtonForMaster = barButtonItem;

Затем, когда вы хотите показать главный контроллер представления, сделайте такой вызов:

[barButtonForMaster.target performSelector: barButtonForMaster.action withObject: barButtonForMaster];

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

[barButtonForMaster.target performSelector: barButtonForMaster.action withObject: barButtonForMaster afterDelay:1];

В этом случае вы можете выполнить селектор прямо в методе делегата с разделенным представлением.

person Rob Elkin    schedule 03.05.2012
comment
Спасибо. Я делаю это с вашим кодом плюс мой предыдущий код. Но иногда приложение вылетает. Я думаю, это потому, что я делаю это в делегате splitViewController и, возможно, в некоторых случаях, в контроллере, который он не полностью создал. Теперь я делаю этот код с помощью perfromSelectorAfterDelay и работаю очень хорошо. Спасибо. - person alejandromp; 05.05.2012
comment
Это приведет к предупреждению компилятора об утечке памяти. - person anders; 17.12.2013

Здесь нет предложений для 5.1, но одно для 8.0:

Теперь с iOS8 есть множество новых методов для настройки UISplitViewController.

В вашем случае просто установите правильное значение в preferredDisplayMode, например в masterViewController viewDidLoad.

Цель-C:

- (void)viewDidLoad {
    // configuring splitviewcontroller
    self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;

    //....
}

Swift:

    override func viewDidLoad() {
        self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
    }

Но это, конечно, только iOS8.

person Martin    schedule 09.10.2014
comment
Это приводит к параллельному отображению. Он не показывает главное представление в режиме всплывающего окна, как запрошено OP. - person phatmann; 10.12.2014
comment
@phatmann, я не думаю, что Алехандромп говорил о поповере. Он говорит, мне нужно заставить показать главное всплывающее окно, но на самом деле это ничего не значит. Принимая во внимание контекст, он действительно говорит об отображении основного вида рядом в портретном режиме, как и в альбомном. - person Martin; 25.06.2015
comment
также можно подробно вызвать ViewController - person fujianjin6471; 23.12.2017

Расширяя ответ Роба, это хорошо работает для меня (на подробном экране viewDidLoad):

//If in portrait mode, display the master view
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
    [self.navigationItem.leftBarButtonItem.target performSelector:self.navigationItem.leftBarButtonItem.action withObject:self.navigationItem];
}

Нет необходимости получать отдельную ссылку, используя вместо этого self.navigationItem.leftBarButtonItem

person Setomidor    schedule 06.11.2012
comment
это потрясающе и отлично работает! это дает мне предупреждение, PerformSelector может вызвать утечку, потому что его селектор неизвестен, знаете ли вы, почему и что с этим делать? - person BObereder; 12.03.2013
comment
AFAIK компилятор анализирует вызовы методов и добавляет код для управления счетчиками ссылок ARC (для управления сборкой мусора). Вызов такого метода похож на использование отражений в Java (выполняется во время выполнения), поэтому в этом случае компилятор не может выполнять свою магию refCount. Однако до тех пор, пока вызываемый метод не возвращает какой-либо выделенный объект (что может быть утечкой), проблем не возникнет. В этом случае мы ничего не возвращаем из вызываемого метода. Чтобы избежать этого предупреждения, см .: Learningipadprogramming. ru / 2012/04/03 / - person Setomidor; 13.03.2013
comment
Это не сработает, если в контроллер подробного представления ничего не загружено, что было бы основным моментом, заставляющим показать мастер. - person Victor Engel; 09.09.2014
comment
@VictorEngel - это так, но поскольку этот код переходит в подробное представление, вам необходимо убедиться, что по умолчанию загружено пустое подробное представление. - person Setomidor; 28.11.2014

Для iOS8 проще всего сделать следующее:

 self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;

Я использую это при первом запуске приложения для отображения входа в систему masterViewController. Во всех остальных случаях я использую

self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic
person aquarius68    schedule 29.05.2015

Если он вам нужен при запуске приложения, переопределите этот метод в контроллере детального представления:

-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
    return NO;
}

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

person SeanR    schedule 14.07.2014
comment
Это устарело в iOS 8. - person phatmann; 10.12.2014

Чуть менее хитрый вариант (быстрый):

let btn = self.splitViewController!.displayModeButtonItem()
btn.target?.performSelector(btn.action, withObject: btn)
person maniek    schedule 27.02.2016

Я использую это решение:
В splitViewController в viewDidLoad установите displayMode на .primaryOverlay

override func viewDidLoad() {
    if self.isCollapsed == false, self.displayMode == .primaryHidden {
        self.preferredDisplayMode = .primaryOverlay
    }
}

И в viewWillAppear снова установил .automatic

override func viewWillAppear(_ animated: Bool) {
    self.preferredDisplayMode = .automatic
}

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

person Alexey Saechnikov    schedule 15.07.2017

Не нужно хранить глупые ссылки на barButtonItem. Просто вызовите ту же цель / действие. См. Мой ответ https://stackoverflow.com/a/25695923/1021430

Целью является контроллер разделенного представления, а действие - toggleMasterVisible:

person user1021430    schedule 06.09.2014
comment
Этот toggleMasterVisible - частный метод. - person Victor Engel; 09.09.2014