Подтвердить что ты не робот

Скрытие контроллера главного представления с помощью UISplitViewController в iOS8

У меня есть приложение iOS7, основанное на шаблоне главной детали Xcode, которое я переношу на iOS8. Одна область, которая сильно изменилась, - это UISplitViewController.

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

enter image description here

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

В iOS 7 контроллер главного представления был отображен как всплывающее окно и может быть скрыт следующим образом:

[self.masterPopoverController dismissPopoverAnimated:YES];

С iOS 8 мастер больше не является popover, поэтому вышеупомянутый метод не будет работать.

Я попытался отклонить контроллер главного представления:

self.dismissViewControllerAnimated(true, completion: nil)

Или сообщите контроллеру разделенного вида, чтобы отобразить контроллер представления деталей:

self.splitViewController?.showDetailViewController(bookViewController!, sender: self)

Но пока ничего не получилось. Любые идеи?

4b9b3361

Ответ 1

Расширьте UISplitViewController следующим образом:

extension UISplitViewController {
    func toggleMasterView() {
        let barButtonItem = self.displayModeButtonItem()
        UIApplication.sharedApplication().sendAction(barButtonItem.action, to: barButtonItem.target, from: nil, forEvent: nil)
    }
}

В didSelectRowAtIndexPath или prepareForSegue выполните следующие действия:

self.splitViewController?.toggleMasterView()

Это будет плавно перемещать вид мастера в сторону.

У меня возникла идея использовать displayModeButtonItem() из этого сообщения, и я имитирую кран на нем за этот пост.

Я не очень доволен этим решением, так как это похоже на хак. Но он работает хорошо, и, похоже, альтернативы пока нет.

Ответ 2

Используйте preferredDisplayMode. В didSelectRowAtIndexPath или prepareForSegue:

self.splitViewController?.preferredDisplayMode = .PrimaryHidden
self.splitViewController?.preferredDisplayMode = .Automatic

К сожалению, просмотр мастера внезапно исчезает, а не сползает, несмотря на документацию, в которой говорится:

Если изменение значения этого свойства приводит к фактическому изменению текущий режим отображения, контроллер разделенного представления оживляет в результате изменения.

Надеюсь, есть лучший способ сделать это, что на самом деле оживляет изменения.

Ответ 3

Я смог получить желаемое поведение в проекте Xcode 6.3 Master-Detail Application (универсальный), добавив следующий код в метод MasterViewController - prepareForSegue:sender::

if view.traitCollection.userInterfaceIdiom == .Pad && splitViewController?.displayMode == .PrimaryOverlay {
    let animations: () -> Void = {
        self.splitViewController?.preferredDisplayMode = .PrimaryHidden
    }
    let completion: Bool -> Void = { _ in
        self.splitViewController?.preferredDisplayMode = .Automatic
    }
    UIView.animateWithDuration(0.3, animations: animations, completion: completion)
}

Полная реализация - prepareForSegue:sender: должна выглядеть так:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        if let indexPath = self.tableView.indexPathForSelectedRow() {
            let object = objects[indexPath.row] as! NSDate
            let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
            controller.detailItem = object
            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
            controller.navigationItem.leftItemsSupplementBackButton = true

            if view.traitCollection.userInterfaceIdiom == .Pad && splitViewController?.displayMode == .PrimaryOverlay {
                let animations: () -> Void = {
                    self.splitViewController?.preferredDisplayMode = .PrimaryHidden
                }
                let completion: Bool -> Void = { _ in
                    self.splitViewController?.preferredDisplayMode = .Automatic
                }
                UIView.animateWithDuration(0.3, animations: animations, completion: completion)
            }
        }
    }
}

Использование traitCollection также может быть альтернативой/дополнением к displayMode в некоторых проектах. Например, следующий код также работает для проекта Xcode 6.3 Master-Detail Application (универсальный):

let traits = view.traitCollection
if traits.userInterfaceIdiom == .Pad && traits.horizontalSizeClass == .Regular {
    let animations: () -> Void = {
        self.splitViewController?.preferredDisplayMode = .PrimaryHidden
    }
    let completion: Bool -> Void = { _ in
        self.splitViewController?.preferredDisplayMode = .Automatic
    }
    UIView.animateWithDuration(0.3, animations: animations, completion: completion)
}

Ответ 4

В приведенном ниже коде скрывается главный вид с анимацией

UIView.animateWithDuration(0.5) { () -> Void in
            self.splitViewController?.preferredDisplayMode = .PrimaryHidden
        }

Ответ 5

Просто немного улучшив ответы, перечисленные здесь, следующий код работает правильно для меня, и он также обрабатывает анимацию плавно:

extension UISplitViewController {
    func toggleMasterView() {
        var nextDisplayMode: UISplitViewControllerDisplayMode
        switch(self.preferredDisplayMode){
        case .PrimaryHidden:
            nextDisplayMode = .AllVisible
        default:
            nextDisplayMode = .PrimaryHidden
        }
        UIView.animateWithDuration(0.5) { () -> Void in
            self.preferredDisplayMode = nextDisplayMode
        }
    }
}

а затем, как уже упоминалось, вы просто используете расширенную функцию в любом месте в контроллерах View

self.splitViewController?.toggleMasterView()

Ответ 6

Модификация ответов выше этого - все, что мне нужно в методе контроллера подробного представления, который настроил представление:

 [self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModePrimaryHidden];

Конечно, ему не хватает грации анимации.

Ответ 7

Мое решение в Swift 1.2

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
    var screen = UIScreen.mainScreen().currentMode?.size.height
    if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad) || screen >= 2000 && UIDevice.currentDevice().orientation.isLandscape == true  && (UIDevice.currentDevice().userInterfaceIdiom == .Phone){
        performSegueWithIdentifier("showDetailParse", sender: nil)
        self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
    } else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
        performSegueWithIdentifier("showParse", sender: nil)
    }
}

Ответ 8

для iPad добавить кнопку меню, подобную этой

UIBarButtonItem *menuButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"burger_menu"]
                                                                       style:UIBarButtonItemStylePlain
                                                                      target:self.splitViewController.displayModeButtonItem.target
                                                                      action:self.splitViewController.displayModeButtonItem.action];
[self.navigationItem setLeftBarButtonItem:menuButtonItem];

Это отлично работает как в ландшафтном, так и в портретном режимах. Чтобы программно закрыть popover vc, вам просто нужно принудительно активировать действие кнопки

[self.splitViewController.displayModeButtonItem.target performSelector:appDelegate.splitViewController.displayModeButtonItem.action];

Ответ 9

попробуйте

let svc = self.splitViewController
svc.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden