Oh mec, cela me causait un mal de tête pendant quelques jours et je ne savais pas comment faire cela. Le pire, c'est que la création d'un nouveau projet Xcode iOS avec le modèle maître-détail fonctionnait très bien. Heureusement, à la fin, ce petit fait a été la façon dont j'ai trouvé la solution.
Certains articles que j'ai trouvés suggèrent que la solution consiste à implémenter la nouvelle primaryViewControllerForCollapsingSplitViewController:
méthode UISplitViewControllerDelegate
. J'ai essayé cela en vain. Ce qu'Apple fait dans le modèle maître-détail qui semble fonctionner, c'est implémenter la nouvelle splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
méthode de délégué (prenez une grande respiration pour dire tout cela) (encore une fois UISplitViewControllerDelegate
). Selon la documentation , cette méthode:
Demande au délégué d'ajuster le contrôleur de vue principal et d'incorporer le contrôleur de vue secondaire dans l'interface réduite.
Assurez-vous de lire la partie discussion de cette méthode pour plus de détails.
La façon dont Apple gère cela est:
- (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;
}
}
Cette implémentation fait essentiellement ce qui suit:
- Si
secondaryViewController
c'est ce à quoi nous nous attendons (a UINavigationController
), et cela montre ce que nous attendons (un DetailViewController
- votre contrôleur de vue), mais n'a pas de modèle ( detailItem
), alors " Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
"
- Sinon, retournez "
NO
pour laisser le contrôleur de vue fractionnée essayer d'incorporer le contenu du contrôleur de vue secondaire dans l'interface réduite"
Les résultats sont les suivants pour l'iPhone en portrait (en commençant en portrait ou en tournant en portrait - ou plus précisément en classe de taille compacte):
- Si votre vue est correcte
- et a un modèle, montre le contrôleur de vue de détail
- mais n'a pas de modèle, affichez le contrôleur de vue maître
- Si votre vue n'est pas correcte
- afficher le contrôleur de vue maître
Clair comme de la boue.
UISplitViewController
- classé et reviens toujoursYES
de cette méthode, puis j'ai simplement changé la classe de vue fractionnée dans Storyboard, car je veux toujours montrer le maître sur iPhone en portrait. :)UISplitViewController
mais j'ai trouvé que cela ne fonctionnait pas:splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
n'a jamais été appelé. Au lieu de cela, j'ai copié le modèle d'Apple et l'ai mis dans l'AppDelagate. Cela a nécessité quelques modifications pour créer également UISplitViewControllerapplication didFinishLaunchingWithOptions:
(où j'ai également copié le modèle d'Apple).splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
ne suis jamais appelé. Il semble que le délégué est correctement défini laapplicationDidFinishLaunchingWithOptions:
méthode de mon délégué d'application . Est-ce que quelqu'un d'autre a vu ce problème et n'a PAS eu cette solution?Voici la réponse acceptée dans Swift. Créez simplement cette sous-classe et attribuez-la à votre splitViewController dans votre storyboard.
la source
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
Version Swift de la bonne réponse de Mark S
Tel que fourni par le modèle Master-Detail d'Apple.
Clarification
(Ce que Mark S a dit était légèrement déroutant)
Cette méthode déléguée est appelée
splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:
, car c'est ce qu'elle fait. Lors du passage à une taille de largeur plus compacte (par exemple lors de la rotation du téléphone du paysage au portrait), il doit réduire le contrôleur de vue fractionnée en un seul d'entre eux.Cette fonction renvoie un booléen pour décider si elle doit réduire le détail et afficher le maître ou non.
Donc, dans notre cas, nous déciderons en fonction de la sélection ou non d'un détail. Comment savons-nous si notre détail est sélectionné? Si nous suivons le modèle Master-Detail d'Apple, le contrôleur de vue détaillée devrait avoir une variable facultative contenant les informations détaillées, donc si c'est nul (.Aucun), il n'y a encore rien de sélectionné et nous devrions afficher le maître afin que l'utilisateur puisse sélectionner quelque chose.
C'est tout.
la source
Apple's Master-Detail template
, il n'est pas destiné à être génial ou concis, mais simplement factuel. :)Dans la documentation , vous devez utiliser un délégué pour dire au de
UISplitViewController
ne pas incorporer la vue détaillée dans "l'interface réduite" (c'est-à-dire le "mode Portrait" dans votre cas). Dans Swift 4, la méthode déléguée à implémenter pour cela a été renommée:la source
.m:
la source
Mon application a été écrite en Swift 2.x et pourrait bien fonctionner. Après l'avoir converti en Swift 3.0 (à l'aide du convertisseur XCode), il commence à afficher les détails au lieu du maître en mode portrait. Le problème est que le nom de la fonction splitViewController n'est pas modifié pour correspondre au nouveau UISplitViewControllerDelegate.
Après avoir modifié le nom de cette fonction manuellement, mon application peut désormais fonctionner correctement:
la source
self.delegate = self
sur laviewDidLoad
méthode.Si vous n'avez pas de valeurs par défaut à afficher dans le contrôleur de vue détaillée, vous pouvez simplement supprimer la transition par défaut entre SplitViewController et votre UIViewController de détail dans le storyboard. Cela le fera toujours entrer dans Master View Controller en premier.
L'effet secondaire de ceci est qu'au lieu de voir deux vues en mode paysage, vous verrez une vue en taille réelle dans SplitViewController jusqu'à ce que Show Detail Segue dans le contrôleur de vue maître soit déclenché.
la source
Pour toutes les personnes qui n'ont pas pu trouver la section vendredi de cs193p:
Dans Swift 3.1.1, créer une sous-classe de UISplitViewController et implémenter l'une de ses méthodes de délégué a fonctionné pour moi comme un charme:
Mon storyboard
la source
public func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
À mon avis, vous devriez résoudre ce problème plus générique. Vous pouvez sous-classer UISplitViewController et implémenter un protocole dans les contrôleurs de vue intégrés.
Exemple d'implémentation dans UITableViewController:
J'espère que ça aide. Vous pouvez donc réutiliser cette classe et avoir juste besoin d'implémenter un protocole.
la source
Supprimez simplement DetailViewController des contrôleurs SplitView lorsque vous en avez besoin pour démarrer à partir de Master.
la source
Cela a fonctionné pour moi sur iOS-11 et Swift 4:
la source
La fonction est renommée dans les nouvelles versions de Swift, donc ce code fonctionne sur Swift 4:
la source
Solution Xamarin / C #
la source
Définissez simplement la
preferredDisplayMode
propriété deUISplitViewController
sur.allVisible
la source