tiene retrato normal modo aparece activar ios interface-builder ios8 uisplitviewcontroller master-detail

ios - aparece - modo retrato iphone 8 normal



UISplitViewController en vertical en iPhone muestra detalles de VC en lugar de master (14)

Estoy usando un Storyboard universal en Xcode 6, dirigido a iOS 7 y superior. Implementé un UISplitViewController que ahora es compatible de forma nativa en iPhone con iOS 8, y Xcode lo respaldará automáticamente para iOS 7. Funciona realmente bien, excepto cuando inicia la aplicación en iPhone en modo vertical con iOS 8, el detalle de la vista dividida el controlador de vista se muestra cuando esperaba ver por primera vez el controlador de vista maestro. Creí que esto era un error con iOS 8 porque cuando ejecutas la aplicación en iOS 7, muestra correctamente el controlador de vista maestro. Pero iOS 8 ahora es GM y esto todavía está ocurriendo. ¿Cómo puedo configurarlo de modo que cuando el controlador de vista dividida se va a colapsar (solo se muestra un controlador de vista en la pantalla), cuando se muestra el controlador de vista dividida, muestra el controlador de vista maestro, no el detalle?

He creado este controlador de vista dividida en Interface Builder. El controlador de vista dividida es el primer controlador de vista dentro de un controlador de barra de pestañas. Tanto el VC maestro como el de detalle son controladores de navegación con controladores de vista de tabla incrustados en su interior.


Solución Xamarin / C #

public partial class MainSplitViewController : UISplitViewController { public MainSplitViewController(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); Delegate = new MainSplitViewControllerDelegate(); } } public class MainSplitViewControllerDelegate : UISplitViewControllerDelegate { public override bool CollapseSecondViewController(UISplitViewController splitViewController, UIViewController secondaryViewController, UIViewController primaryViewController) { return true; } }


Versión rápida de la respuesta correcta de Mark S

Según lo provisto por la plantilla Master-Detail de Apple.

func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool { guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } if topAsDetailController.detailItem == nil { // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return true } return false }

Aclaración

(Lo que dijo Mark S fue un poco confuso)

Este método delegado se llama splitViewController: collapseSecondaryViewController: ontoPrimaryViewController: porque eso es lo que hace. Al cambiar a un tamaño de ancho más compacto (por ejemplo, al girar el teléfono de horizontal a vertical), debe contraer el controlador de vista dividida en solo uno de ellos.

Esta función devuelve un valor booleano para decidir si debe contraer el Detalle y mostrar el Maestro o no.

Entonces, en nuestro caso, decidiremos en función de si se seleccionó un detalle o no. ¿Cómo sabemos si se seleccionan nuestros detalles? Si seguimos la plantilla Master-Detail de Apple, el controlador de vista detallada debe tener una variable opcional que tenga la información detallada, por lo que si es nulo (.Ninguno), todavía no hay nada seleccionado y deberíamos mostrar el Master para que el usuario pueda seleccionar algo.

Eso es.


Aquí está la respuesta aceptada en Swift. Simplemente cree esta subclase y asígnela a su splitViewController en su guión gráfico.

//GlobalSplitViewController.swift import UIKit class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController!, ontoPrimaryViewController primaryViewController: UIViewController!) -> Bool{ return true } }


De la documentation , debe utilizar un delegado para indicarle al UISplitViewController no incorpore la vista detallada en la "interfaz contraída" (es decir, el "modo vertical" en su caso). En Swift 4, se ha cambiado el nombre del método delegado para implementar:

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { return true }


En mi opinión, deberías resolver este problema más genérico. Puede subclasificar el UISplitViewController e implementar un protocolo en los controladores de vista integrados.

class MasterShowingSplitViewController: UISplitViewController { override func viewDidLoad() { super.viewDidLoad() delegate = self } } extension MasterShowingSplitViewController: UISplitViewControllerDelegate { func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool { guard let masterNavigationController = primaryViewController as? UINavigationController, master = masterNavigationController.topViewController as? SplitViewControllerCollapseProtocol else { return true } return master.shouldShowMasterOnCollapse() } } protocol SplitViewControllerCollapseProtocol { func shouldShowMasterOnCollapse() -> Bool }

Implementación de ejemplo en UITableViewController:

extension SettingsTableViewController: SplitViewControllerCollapseProtocol { func shouldShowMasterOnCollapse() -> Bool { return tableView.indexPathForSelectedRow == nil } }

Espero eso ayude. Entonces puede reutilizar esta clase y solo necesita implementar un protocolo.


Esto funcionó para mí en iOS-11 y Swift 4:

//Following code in application didFinishLaunching (inside Application Delegate) guard let splitViewController = window?.rootViewController as? UISplitViewController, let masterNavVC = splitViewController.viewControllers.first as? UINavigationController, let masterVC = masterNavVC.topViewController as? MasterViewController else { fatalError() } splitViewController.delegate = masterVC //Following code in MasterViewController class extension MasterViewController:UISplitViewControllerDelegate { func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { return true } }


La función cambia de nombre en las nuevas versiones de Swift, por lo que este código funciona en Swift 4:

import UIKit class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { return true } }


Mi aplicación fue escrita en Swift 2.xy podría funcionar bien. Después de convertirlo a Swift 3.0 (usando el convertidor XCode), comienza a mostrar detalles primero en lugar de master en modo vertical. El problema es que el nombre de la función splitViewController no se cambia para que coincida con la nueva de UISplitViewControllerDelegate.

Después de cambiar el nombre de esa función manualmente, mi aplicación ahora puede funcionar correctamente:

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } if topAsDetailController.game == nil { // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return true } return false }


Oh hombre, esto me estaba causando dolor de cabeza durante unos días y no podía encontrar la manera de hacerlo. La peor parte fue que crear un nuevo proyecto Xcode iOS con la plantilla master-detail funcionó bien. Afortunadamente, al final, ese pequeño hecho fue cómo encontré la solución.

Hay algunas publicaciones que he encontrado que sugieren que la solución es implementar el nuevo primaryViewControllerForCollapsingSplitViewController: método en UISplitViewControllerDelegate . Lo intenté en vano. Lo que Apple hace en la plantilla de detalles maestros que parece funcionar es implementar el nuevo splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: delegate (de nuevo en UISplitViewControllerDelegate ). Según los docs , este método:

Pide al delegado que ajuste el controlador de vista primario e incorpore el controlador de vista secundario en la interfaz contraída.

Asegúrese de leer la parte de discusión de ese método para obtener detalles más específicos.

La forma en que Apple maneja esto es:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]] && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) { // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return YES; } else { return NO; } }

Esta implementación básicamente hace lo siguiente:

  1. Si secondaryViewController es lo que esperamos (un UINavigationController ), y muestra lo que esperamos (un DetailViewController - su controlador de vista), pero no tiene modelo ( detailItem ), entonces " Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. " Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
  2. De lo contrario, devuelva " NO para permitir que el controlador de vista dividida intente incorporar el contenido del controlador de vista secundario en la interfaz contraída"

Los resultados son los siguientes para el iPhone en vertical (ya sea comenzando en vertical o girando a vertical, o una clase de tamaño compacta más precisa):

  1. Si tu opinión es correcta
    • y tiene un modelo, muestra el controlador de vista detallada
    • pero no tiene modelo, muestra el controlador de vista maestro
  2. Si su punto de vista no es correcto
    • mostrar el controlador de vista maestro

Claro como el barro.


Para todas las personas que no pudieron encontrar la sección del viernes de cs193p:

En Swift 3.1.1, crear una subclase de UISplitViewController e implementar uno de sus métodos delegados me funcionó de maravilla:

class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { return true } }

Mi storyboard


Si no tiene valores predeterminados para mostrar en el controlador de vista detallada, simplemente puede eliminar el segue predeterminado entre el SplitViewController y su UIViewController detallado en el tablero de historias. Esto hará que siempre entre primero en Master View Controller.

El efecto secundario de esto es que, en lugar de ver dos vistas en horizontal, verá una vista en tamaño completo en SplitViewController hasta que se active Mostrar detalle Segue en el controlador de vista maestro.


Simplemente configure la propiedad preferredDisplayMode de UISplitViewController en .allVisible

class MySplitViewController: UISplitViewController { override func viewDidLoad() { super.viewDidLoad() self.preferredDisplayMode = .allVisible } }


Simplemente quite DetailViewController de los controladores SplitView cuando lo necesite para comenzar desde Master.

UISplitViewController *splitViewController = (UISplitViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SETTINGS"]; splitViewController.delegate = self; [self.navigationController presentViewController:splitViewController animated:YES completion:nil]; if (IPHONE) { NSMutableArray * cntlrs = [splitViewController.viewControllers mutableCopy]; [cntlrs removeLastObject]; splitViewController.viewControllers = cntlrs; }


#import <UIKit/UIKit.h> @interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate> @end

.metro:

#import "SplitProductView.h" #import "PriceDetailTableView.h" @interface SplitProductView () @end @implementation SplitProductView - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.delegate = self; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ - (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[PriceDetailTableView class]] //&& ([(PriceDetailTableView *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil) ) { // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return YES; } else { return NO; } } @end