web-dev-qa-db-fra.com

Masquage du contrôleur de vue principal avec UISplitViewController dans iOS8

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é:

enter image description here

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?

43
ColinE

É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.

59
phatmann

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.

10
Vinay Jain

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)
}
9
Imanou Petit

Le code ci-dessous masque la vue principale avec animation

UIView.animateWithDuration(0.5) { () -> Void in
            self.splitViewController?.preferredDisplayMode = .PrimaryHidden
        }
7
jithinroy

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()
5
Santiago Bendavid

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)
}
1
Andy G

essayer

laissez svc = self.splitViewController 
 svc.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
1
daren

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.

1
Tim

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];
0
coder1087

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)
    }
}
0
Alexander Khitev