Скрытие контроллера главного представления с помощью 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)
Но пока ничего не получилось. Любые идеи?
Ответы
Ответ 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