J'ai une application iOS7, basée sur le modèle maître-détail Xcode, que je porte sur iOS8. Un domaine qui a beaucoup changé est le UISplitViewController
.
En mode portrait, si l'utilisateur appuie sur le contrôleur de vue de détail, le contrôleur de vue principal est rejeté:
Je voudrais également pouvoir masquer par programmation le contrôleur de vue principal si l'utilisateur appuie sur une ligne.
Dans iOS 7, le contrôleur de vue principal était affiché sous forme de fenêtre contextuelle et pouvait être masqué comme suit:
[self.masterPopoverController dismissPopoverAnimated:YES];
Avec iOS 8, le maître n'est plus un popover, donc la technique ci-dessus ne fonctionnera pas.
J'ai essayé de rejeter le contrôleur de vue principal:
self.dismissViewControllerAnimated(true, completion: nil)
Ou demandez au contrôleur de vue fractionnée d'afficher le contrôleur de vue des détails:
self.splitViewController?.showDetailViewController(bookViewController!, sender: self)
Mais rien n'a fonctionné jusqu'à présent. Des idées?
Étendez UISplitViewController comme suit:
extension UISplitViewController {
func toggleMasterView() {
let barButtonItem = self.displayModeButtonItem()
UIApplication.sharedApplication().sendAction(barButtonItem.action, to: barButtonItem.target, from: nil, forEvent: nil)
}
}
Dans didSelectRowAtIndexPath
ou prepareForSegue
, procédez comme suit:
self.splitViewController?.toggleMasterView()
Cela fera glisser doucement la vue principale hors du chemin.
J'ai eu l'idée d'utiliser le displayModeButtonItem () de ce post et je simule un tapotement dessus ce post .
Je ne suis pas vraiment satisfait de cette solution, car elle semble être un hack. Mais cela fonctionne bien et il ne semble pas encore y avoir d'alternative.
Utilisez preferredDisplayMode
. Dans didSelectRowAtIndexPath
ou prepareForSegue
:
self.splitViewController?.preferredDisplayMode = .PrimaryHidden
self.splitViewController?.preferredDisplayMode = .Automatic
Malheureusement, la vue principale disparaît brusquement au lieu de glisser, malgré la documentation indiquant:
Si la modification de la valeur de cette propriété entraîne une modification réelle du mode d'affichage actuel, le contrôleur de vue fractionnée anime la modification résultante.
Espérons qu'il existe une meilleure façon de le faire qui anime réellement le changement.
J'ai pu avoir le comportement souhaité dans un projet Xcode 6.3 Master-Detail Application (universal) en ajoutant le code suivant dans la méthode - prepareForSegue:sender:
De MasterViewController
:
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)
}
L'implémentation complète de - prepareForSegue:sender:
Devrait ressembler à ceci:
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)
}
}
}
}
L'utilisation de traitCollection
peut également être une alternative/un complément à displayMode
dans certains projets. Par exemple, le code suivant fonctionne également pour un projet 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)
}
Le code ci-dessous masque la vue principale avec animation
UIView.animateWithDuration(0.5) { () -> Void in
self.splitViewController?.preferredDisplayMode = .PrimaryHidden
}
Juste en améliorant un peu les réponses répertoriées ici, le code suivant fonctionne correctement pour moi et gère également l'animation en douceur:
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
}
}
}
puis, comme mentionné, vous utilisez simplement la fonction étendue n'importe où dans vos contrôleurs View
self.splitViewController?.toggleMasterView()
Mise à jour de Swift 4:
Insérez-le dans prepare (pour segue: ...
if splitViewController?.displayMode == .primaryOverlay {
let animations: () -> Void = {
self.splitViewController?.preferredDisplayMode = .primaryHidden
}
let completion: (Bool) -> Void = { _ in
self.splitViewController?.preferredDisplayMode = .automatic
}
UIView.animate(withDuration: 0.3, animations: animations, completion: completion)
}
essayer
laissez svc = self.splitViewController svc.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
La modification des réponses ci-dessus est tout ce dont j'avais besoin dans une méthode de mon contrôleur de vue détaillée qui a configuré la vue:
[self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModePrimaryHidden];
Bien sûr, il lui manque la grâce de l'animation.
pour iPad ajouter un bouton de menu comme celui-ci
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];
Cela fonctionne très bien avec le mode paysage et portrait. Pour fermer par programme le popover vc, il vous suffit de forcer l'action du bouton comme ceci
[self.splitViewController.displayModeButtonItem.target performSelector:appDelegate.splitViewController.displayModeButtonItem.action];
Ma solution dans le 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)
}
}