objective c - Ocultar el controlador de vista maestra con UISplitViewController en iOS8
objective-c swift (9)
El código a continuación oculta la vista maestra con animación
UIView.animateWithDuration(0.5) { () -> Void in
self.splitViewController?.preferredDisplayMode = .PrimaryHidden
}
Tengo una aplicación iOS7, que estaba basada en la plantilla de detalles maestros de Xcode, que estoy migrando a iOS8. Un área que ha cambiado mucho es UISplitViewController
.
Cuando está en modo vertical, si el usuario toca el controlador de vista detallada, el controlador de vista maestra se descarta:
También me gustaría poder ocultar el controlador de vista maestra mediante programación si el usuario toca una fila.
En iOS 7, el controlador de vista maestra se mostró como una ventana emergente y podría ocultarse de la siguiente manera:
[self.masterPopoverController dismissPopoverAnimated:YES];
Con iOS 8, el maestro ya no es un popover, por lo que la técnica anterior no funcionará.
Intenté descartar el controlador de vista maestra:
self.dismissViewControllerAnimated(true, completion: nil)
O indique al controlador de vista dividida que muestre el controlador de visualización de detalles:
self.splitViewController?.showDetailViewController(bookViewController!, sender: self)
Pero nada ha funcionado hasta ahora. ¿Algunas ideas?
Extienda el UISplitViewController de la siguiente manera:
extension UISplitViewController {
func toggleMasterView() {
let barButtonItem = self.displayModeButtonItem()
UIApplication.sharedApplication().sendAction(barButtonItem.action, to: barButtonItem.target, from: nil, forEvent: nil)
}
}
En didSelectRowAtIndexPath
o prepareForSegue
, haga lo siguiente:
self.splitViewController?.toggleMasterView()
Esto deslizará suavemente la vista maestra fuera del camino.
Tengo la idea de usar displayModeButtonItem () desde esta publicación y estoy simulando un toque en esta publicación .
No estoy muy contento con esta solución, ya que parece un truco. Pero funciona bien y parece que todavía no hay alternativa.
Mi solución en 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)
}
}
Modificar las respuestas anteriores es todo lo que necesitaba en un método de mi controlador de vista detallada que configuraba la vista:
[self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModePrimaryHidden];
Por supuesto, carece de la gracia de la animación.
Pude tener el comportamiento deseado en un proyecto Xcode 6.3 Master-Detail Application (universal) agregando el siguiente código en el método MasterViewController
''s - 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)
}
La implementación completa de - prepareForSegue:sender:
debería verse así:
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)
}
}
}
}
Usar traitCollection
también puede ser una alternativa / complemento de displayMode
en algunos proyectos. Por ejemplo, el siguiente código también funciona para un proyecto Xcode 6.3 Master-Detail Application (universal) :
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)
}
Solo estoy mejorando un poco las respuestas enumeradas aquí, el siguiente código funciona correctamente para mí y también maneja la animación sin problemas:
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
}
}
}
y luego, como se mencionó, solo usa la función extendida en cualquier lugar de sus controladores View
self.splitViewController?.toggleMasterView()
Use preferredDisplayMode
. En didSelectRowAtIndexPath
o prepareForSegue
:
self.splitViewController?.preferredDisplayMode = .PrimaryHidden
self.splitViewController?.preferredDisplayMode = .Automatic
Lamentablemente, la vista maestra desaparece bruscamente en lugar de deslizarse, a pesar de la documentación que indica:
Si al cambiar el valor de esta propiedad se produce un cambio real en el modo de visualización actual, el controlador de vista dividida anima el cambio resultante.
Con suerte, hay una mejor manera de hacer esto que realmente anima el cambio.
para iPad agrega el botón de Menú como este
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];
Este funciona muy bien con el modo paisaje y retrato. Para cerrar programáticamente el popover vc solo necesita forzar la acción del botón de esta manera
[self.splitViewController.displayModeButtonItem.target performSelector:appDelegate.splitViewController.displayModeButtonItem.action];
tratar
let svc = self.splitViewController svc.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden