Mise en œuvre du confinement des conteneurs - Contrôleur de menu coulissant

Dans ce tutoriel, nous allons implémenter une version minimaliste de l'interface utilisateur de style Facebook / Path. L'objectif sera de comprendre comment utiliser le confinement du contrôleur de vue afin d'implémenter un flux personnalisé dans votre application..


Aperçu théorique

Les contrôleurs de vue constituent un élément essentiel de toute application iOS, quelle que soit sa taille, sa taille, sa simplicité ou sa complexité. Ils fournissent la "logique de liaison" entre le modèle de données de votre application et l'interface utilisateur.

De manière générale, il existe deux types de contrôleurs de vue:

  • Contrôleurs de vue du contenu: Ceux-ci sont responsables de l'affichage et de la gestion du contenu visible.
  • Contrôleurs de conteneur: Ceux-ci gèrent les contrôleurs de vue du contenu et sont responsables de la structure et du flux de l'application..

Un contrôleur de conteneur peut avoir son propre composant visible, mais il fonctionne essentiellement comme hôte pour les contrôleurs de vue de contenu. Les contrôleurs de conteneur servent à "trafiquer" les allées et venues des contrôleurs de vue de contenu.

UINavigationController, UITabBarController et UIPageViewController sont des exemples de contrôleurs de vue de conteneur fournis avec le SDK iOS. Examinez les différences entre les trois applications en termes de flux d'applications. Le contrôleur de navigation est idéal pour une application de type exploration en profondeur, dans laquelle la sélection effectuée par l'utilisateur dans un écran affecte les choix présentés dans l'écran suivant. Le contrôleur de barre d’onglet est idéal pour les applications avec des fonctionnalités indépendantes, permettant un basculement pratique en appuyant simplement sur un bouton d’onglet. Enfin, le contrôleur de visualisation de page présente une métaphore de livre, permettant à l'utilisateur de basculer entre les pages de contenu..

Il est important de garder à l'esprit ici qu'un écran contenant du contenu présenté par l'un de ces contrôleurs de vue de conteneur doit lui-même être géré, à la fois en termes de données dont il est dérivé (le modèle) et de la présentation à l'écran. (la vue), qui serait encore une fois le travail d’un contrôleur de vue. Nous parlons maintenant de contrôleurs de vue de contenu. Dans certaines applications, en particulier sur l'iPad, car son écran plus grand permet d'afficher plus de contenu à la fois, il peut même être nécessaire de gérer différentes vues à l'écran. Cela nécessite plusieurs contrôleurs de vue à l'écran à la fois. Tout cela implique que les contrôleurs de vue dans une application bien conçue doivent être implémentés de manière hiérarchique, les contrôleurs de vue de conteneur et de contenu jouant leurs rôles respectifs..

Avant iOS 5, il n'existait aucun moyen de déclarer une relation hiérarchique (c'est-à-dire parent-enfant) entre deux contrôleurs de vue et, par conséquent, aucun moyen "approprié" d'implémenter un flux d'application personnalisé. Il fallait soit se débrouiller avec les types intégrés, soit le faire de manière aléatoire, consistant essentiellement à coller des vues gérées par un contrôleur de vue dans la hiérarchie de vues de la vue gérée par un autre contrôleur de vue. Cela créerait des incohérences. Par exemple, une vue finirait par être dans la hiérarchie de vues de deux contrôleurs sans que l'un ou l'autre de ces contrôleurs ne reconnaisse l'autre, ce qui conduit parfois à un comportement étrange. Le confinement a été introduit dans iOS 5 et légèrement amélioré dans iOS 6. Il permet de formaliser la notion de contrôleurs de vue parent et enfant dans une hiérarchie.. Essentiellement, le confinement correct du contrôleur de vue exige que si la vue B soit une sous-vue (enfant) de la vue A et si elles ne sont pas gérées par le même contrôleur de vue, le contrôleur de vue de B doit alors être défini sur l'enfant du contrôleur de vue de B.

Vous pourriez vous demander si le confinement du contrôleur de vue offre un avantage concret en plus de l'avantage de la conception hiérarchique dont nous avons parlé. La réponse est oui. N'oubliez pas que lorsqu'un contrôleur de vue s'affiche à l'écran ou s'en va, il peut être nécessaire de configurer ou de supprimer des ressources, de nettoyer, d'extraire ou de sauvegarder des informations depuis / vers le système de fichiers. Nous connaissons tous les rappels d’apparence. En déclarant explicitement la relation parent-enfant, nous nous assurons que le contrôleur parent transmettra les rappels à ses enfants à chaque activation ou désactivation de l'écran. Les rappels de rotation doivent également être transférés. Lorsque l'orientation change, tous les contrôleurs de vue à l'écran doivent être informés pour pouvoir ajuster leur contenu de manière appropriée..

Qu'est-ce que tout cela implique, en termes de code? Les contrôleurs de vue ont un NSArray propriété appelée childViewControllers et nos responsabilités incluent l'ajout et la suppression de contrôleurs de vue enfant à et de ce tableau dans le parent en appelant les méthodes appropriées. Ces méthodes incluent addChildViewController (appelé le parent) et removeFromParentViewController (appelé à l'enfant) lorsque nous cherchons à faire ou défaire la relation parent-enfant. Deux messages de notification sont également envoyés au contrôleur de vue enfant au début et à la fin du processus d'ajout / suppression. Ceux-ci sont willMoveToParentViewController: et didMoveToParentViewController:, envoyé avec le contrôleur parent approprié comme argument. L'argument est néant, si l'enfant est enlevé. Comme nous le verrons, l’un de ces messages nous sera envoyé automatiquement tandis que l’autre sera sous notre responsabilité. Cela dépend si nous ajoutons ou supprimons l'enfant. Nous étudierons la séquence exacte sous peu lorsque nous implémenterons des choses dans le code. Le contrôleur enfant peut répondre à ces notifications en implémentant les méthodes correspondantes s'il doit faire quelque chose en préparation de ces événements..

Nous devons également ajouter / supprimer les vues associées au contrôleur de vue enfant dans la hiérarchie du parent, en utilisant des méthodes telles que addSubview: ou removeFromSuperview), y compris l'exécution d'éventuelles animations d'accompagnement. Il y a une méthode pratique (-) transitionFromViewController: toViewController: durée: options: animations: complétion: cela nous permet de rationaliser le processus de permutation des contrôleurs de vue enfant à l'écran avec des animations. Nous examinerons les détails exacts lorsque nous écrirons le code - qui est le suivant!


1. Créer un nouveau projet

Créer une nouvelle application iOS dans Xcode basée sur le "Application vide"modèle. Faites-en une application iOS avec ARC activé. Appelez-le VCContainmentTut.

Créer un nouveau projet

2. Implémentation du contrôleur de vue du conteneur

Créez une nouvelle classe appelée RootController. En faire un UIViewController sous-classe. Assurez-vous que toutes les cases à cocher sont désélectionnées. Ce sera notre sous-classe de contrôleur de vue de conteneur.


Remplacer le code dans RootViewController.h avec ce qui suit.

 #importation  @interface RootController: UIViewController // (1) - (id) initWithViewControllers: (NSArray *) viewControllers andMenuTitles: (NSArray *) titres; // (2) @end

Notre contrôleur de conteneur aura une vue sous forme de tableau qui fonctionnera comme notre menu. En tapant sur n'importe quelle cellule, le contrôleur de vue actuellement visible sera remplacé par celui sélectionné par le robinet de l'utilisateur..

Se référant aux points dans le code,

  1. Notre contrôleur racine sert également de délégué et de source de données du menu (c'est-à-dire celui de la vue de table)..
  2. Nous proposons une API extrêmement simple (en ce qui concerne notre utilisateur de classe conteneur) consistant en un initialiseur qui répertorie les contrôleurs de vue que notre contrôleur racine doit contenir, ainsi qu’une liste de chaînes représentant les titres de chaque contrôleur de vue du système. menu. C’est pour que nous puissions nous concentrer sur les bases. Une fois que vous avez compris ces éléments, vous pouvez personnaliser l’API à votre guise..

Jetons un coup d'oeil en avant pour voir à quoi notre produit fini ressemblera afin que vous ayez une image mentale à associer à la mise en œuvre..


Cela nous aidera à comprendre que notre contrôleur de vue de conteneur est assez similaire à un contrôleur de vue à onglet. Chaque élément du menu correspond à un contrôleur de vue indépendant. La différence entre nos "menu coulissant"contrôleur et le contrôleur de tabulation sont visuels pour la plupart. La phrase"menu coulissant"est un peu impropre, car c’est en fait le contrôleur de vue du contenu qui glisse pour masquer ou afficher le menu situé en dessous.

Passons maintenant à l'implémentation, remplacez tout le code dans RootController.m par le code suivant.

 #define kExposedWidth 200.0 #define kMenuCellID @ "MenuCell" #import "RootController.h" @interface RootController () @property (nonatomic, strong) UITableView * menu; @property (nonatomic, strong) NSArray * viewControllers; @property (nonatomic, strong) NSArray * menuTitles; @property (nonatomic, assign) NSInteger indexOfVisibleController; @property (nonatomic, assign) BOOL isMenuVisible; @end @implementation RootController - (id) initWithViewControllers: (NSArray *) viewControllers andMenuTitles: (NSArray *) menuTitles if (self = [super init]) NSAssert (self.viewControllers.count == self.menuTitles.count, @ "Il doit y avoir un et un seul titre de menu correspondant à chaque contrôleur de vue!"); // (1) NSMutableArray * tempVCs = [NSMutableArray arrayWithCapacity: viewControllers.count]; self.menuTitles = [copie de menuTitles]; for (UIViewController * vc dans viewControllers) // (2) if (! [vc isMemberOfClass: [classe UINavigationController]]) tempVCs addObject: [[UINavigationController alloc]] initWithRootViewController: vc]];  else [tempVCs addObject: vc]; UIBarButtonItem * discoverMenuBarButtonItem = [[UIBarButtonItem alloc]] initWithTitle: @ style "Menu": UIBarButtonItemStylePlain cible: auto-action: @selector (toggleMenuVisibility :)); // (3) UIViewController * topVC = ((UINavigationController *) tempVCs.lastObject) .topViewController; topVC.navigationItem.leftBarButtonItems = [@ [veMenuBarButtonItem] arrayByAddingObjectsFromArray: topVC.navigationItem.leftBarButtonItems];  self.viewControllers = [copie de tempVC]; self.menu = [[UITableView alloc] init]; // (4) self.menu.delegate = self; self.menu.dataSource = self;  retourner soi-même;  - (void) viewDidLoad [super viewDidLoad]; [self.menu registerClass: [Classe UITableViewCell] pourCellReuseIdentifier: kMenuCellID]; self.menu.frame = self.view.bounds; [self.view addSubview: self.menu]; self.indexOfVisibleController = 0; UIViewController * visibleViewController = self.viewControllers [0]; visibleViewController.view.frame = [auto offScreenFrame]; [self addChildViewController: visibleViewController]; // (5) [self.view addSubview: visibleViewController.view]; // (6) self.isMenuVisible = YES; [self adjustContentFrameAccordingToMenuVisibility]; // (7) [self.viewControllers [0] didMoveToParentViewController: self]; // (8) - (void) toggleMenuVisibility: (id) expéditeur // (9) self.isMenuVisible =! Self.isMenuVisible; [self adjustContentFrameAccordingToMenuVisibility];  - (void) adjustContentFrameAccordingToMenuVisibility // (10) UIViewController * visibleViewController = self.viewControllers [self.indexOfVisibleController]; CGSize size = visibleViewController.view.frame.size; if (self.isMenuVisible) [UIView animateWithDuration: 0.5 animations: ^ visibleViewController.view.frame = CGRectMake (kExposedWidth, 0, size.width, size.height); ];  else [UIView animateWithDuration: 0.5 animations: ^ visibleViewController.view.frame = CGRectMake (0, 0, size.width, size.height); ];  - (void) replaceVisibleViewControllerWithViewControllerAtIndex: (NSInteger) index // (11) if (index == self.indexOfVisibleController) return; UIViewController * incomingViewController = self.viewControllers [index]; incomingViewController.view.frame = [auto offScreenFrame]; UIViewController * outgoingViewController = self.viewControllers [self.indexOfVisibleController]; CGRect visibleFrame = self.view.bounds; [outgoingViewController willMoveToParentViewController: nil]; // (12) [self addChildViewController: incomingViewController]; // (13) [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; // (14) [auto transitionFromViewController: outgoingViewController // (15) toViewController: incomingViewController durée: 0.5 options: 0 animations: ^ outgoingViewController.view.frame = [auto offScreenFrame];  complétion: ^ (BOOL terminé) [UIView animateWithDuration: 0.5 animations: ^ [outgoingViewController.view removeFromSuperview]; [self.view addSubview: incomingViewController.view]; incomingViewController.view.frame = visibleFrame; [[UIApplication sharedApplication] endIgnoringInteractionEvents]; // (16)]; [incomingViewController didMoveToParentViewController: self]; // (17) [outgoingViewController removeFromParentViewController]; // (18) self.isMenuVisible = NO; self.indexOfVisibleController = index; ];  // (19): - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return 1;  - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section return self.menuTitles.count;  - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: kMenuCellID]; cell.textLabel.text = self.menuTitles [indexPath.row]; cellule de retour;  - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [self replaceVisibleViewControllerWithViewControllerAtIndex: indexPath.row];  - (CGRect) offScreenFrame return CGRectMake (self.view.bounds.size.width, 0, self.view.bounds.size.width, self.view.bounds.size.height);  @fin

Maintenant, pour une explication du code. Les parties sur lesquelles j'ai mis l'accent sont particulièrement pertinentes pour la mise en œuvre du confinement.

  1. Tout d'abord, l'initialiseur effectue un contrôle simple pour s'assurer que chaque contrôleur de vue a reçu un titre de menu. Nous n'avons effectué aucune vérification de type pour nous assurer que chacun des deux tableaux transmis à l'initialiseur contient le bon type d'objets., UIViewController et NSString types respectivement. Vous pourriez envisager de le faire. Notez que nous maintenons des tableaux pour chacun d’eux, appelés viewControllers, et menuTitres.
  2. Nous voulons qu'il y ait un bouton qui, lorsqu'il est tapé, affiche ou masque le menu. Ma solution simple quant à l'emplacement du bouton consistait à placer tous les contrôleurs de vue que nous avons reçus de l'initialiseur dans un contrôleur de navigation. Cela nous donne une barre de navigation gratuite à laquelle un bouton peut être ajouté, à moins que le contrôleur de vue passé ne soit déjà un contrôleur de navigation, auquel cas nous ne faisons rien de plus..
  3. Nous créons un élément de bouton de barre qui déclenche l'apparence du menu ou le cache en faisant glisser le contrôleur de vue actuellement visible. Nous l’ajoutons à la barre de navigation en déplaçant les boutons existants de la barre de navigation vers la droite. Nous faisons cela parce que le contrôleur de vue ajouté est déjà un contrôleur de navigation avec des boutons de barre préexistants..
  4. Nous instancions notre menu sous forme de tableau et affectons le contrôleur racine lui-même en tant que délégué et source de données..
  5. Dans viewDidLoad, après avoir configuré et ajouté la vue de la table des menus à la vue de notre contrôleur racine, nous introduisons dans notre application le premier contrôleur de vue du viewControllers tableau. En envoyant le addChildViewController: message à notre contrôleur racine, nous assumons notre première responsabilité liée au confinement. Vous devriez savoir que cela provoque le message willMoveToParentViewController: être appelé sur le contrôleur enfant.
  6. Notez que nous devons explicitement ajouter la vue de notre contrôleur enfant à la hiérarchie de vues du parent.!
  7. Nous définissons le menu pour qu'il soit visible au départ et appelons une méthode qui ajuste le cadre du contrôleur d'affichage de contenu visible, en tenant compte de la visibilité du menu. Nous examinerons les détails de cette méthode sous peu.
  8. Une fois que la vue du contrôleur de vue enfant est confortablement installée dans la hiérarchie de vues du parent, nous envoyons le message didMoveToParentViewController au contrôleur enfant ajouté, avec soi, l'instance RootController, en tant qu'argument. Dans notre contrôleur enfant, nous pouvons implémenter cette méthode si nous devons.
  9. Une méthode simple connectée à l'action du bouton de la barre de menus qui modifie la visibilité du menu en ajustant correctement la vue du contrôleur de superposition..
  10. Comme son nom l'indique, adjustContentFrameAccordingToMenuVisibility nous permet d'ajuster le cadre du contrôleur d'affichage du contenu pour nous indiquer si le menu est masqué ou non. Si oui, alors cela recouvre le superview. Sinon, il est déplacé vers la droite par kExposedWidth. J'ai mis ça à 200 points.
  11. Encore une fois, comme l'indique clairement le nom, replaceVisibleViewControllerWithViewControllerAtIndex nous permet d’échanger les contrôleurs de vue et les vues correspondantes de la hiérarchie. Pour terminer notre animation, qui consiste à faire glisser le contrôleur de vue remplacé hors écran vers la droite, puis à importer le contrôleur de remplacement à partir du même endroit, nous définissons des cadres rectangulaires..
  12. willMoveToParentViewController avec néant. Une fois cette étape terminée, ce contrôleur de vue cessera de recevoir les rappels d’apparence et de rotation du parent. Cela a du sens car ce n'est plus une partie active de l'application.
  13. Nous ajoutons le contrôleur de vue entrant en tant qu'enfant au contrôleur racine, comme nous l'avons fait au début..
  14. Nous commençons à ignorer les événements d'interaction utilisateur pour permettre à notre contrôleur de vue de basculer en douceur.
  15. Cette méthode de commodité nous permet d’animer la suppression du contrôleur sortant et l’arrivée du contrôleur entrant tout en effectuant la séquence requise d’événements impliqués dans le processus d’ajout et de suppression du contrôleur de vue enfant. Nous animons la vue du VC sortant pour qu'elle glisse vers la droite et, une fois l'animation terminée, nous la supprimons de la hiérarchie des vues. Nous animons ensuite le contrôleur de vue entrant pour qu'il glisse du même endroit hors écran et occupe la place précédemment occupée par la vue du contrôleur sortant..
  16. Nous permettons à notre application d'accepter les événements d'interaction entrants, car notre permutation de contrôleur de vue est terminée.
  17. Nous informons le contrôleur de vue entrant qu'il a été déplacé vers le contrôleur de conteneur en lui envoyant le message didMoveToParentViewController message avec soi comme argument.
  18. Nous retirons le contrôleur sortant du contrôleur de conteneur en lui envoyant le removeFromParentViewController message. Tu devrais savoir ça didMoveToParentViewController: avec néant comme argument est envoyé pour vous.
  19. Nous implémentons les méthodes de protocole de délégué et de source de données de la vue de la table de menu, qui sont assez simples. Cela comprend le déclenchement de l’étape de permutation du contrôleur de vue (11) lorsqu’une nouvelle cellule est sélectionnée dans le menu via -tableView: didSelectRowAtIndexPath: méthode.

Vous avez peut-être trouvé la séquence d'appels liés à la maîtrise du contrôleur un peu déroutante. Ça aide à résumer.

    Lors de l'ajout d'un contrôleur de vue enfant à un parent:
  • Appel addChildViewController: sur le parent avec l'enfant comme argument. Cela provoque le message willMoveToParentViewController: à envoyer à l'enfant avec le parent comme argument.
  • Ajouter la vue de l'enfant en tant que sous-vue de la vue du parent.
  • Appeler explicitement didMoveToParentViewController: sur l'enfant avec le parent comme argument.
    Lors de la suppression d'un contrôleur de vue enfant de son parent:
  • Appel willMoveToParentViewController: sur l'enfant avec néant comme argument.
  • Retirer la vue de l'enfant de son aperçu.
  • Envoyer removeFromParentViewController à l'enfant. Les causes du message didMoveToParentViewController avec néant comme argument à envoyer à l'enfant en votre nom.

3. Test

Testons les différents types de contrôleurs de vue ajoutés à notre contrôleur racine! Créer une nouvelle sous-classe de UIViewController appelé ViewController, garder toutes les options décochées.

Remplacez le code dans ViewController.m par le code suivant.

 #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void) willMoveToParentViewController: (UIViewController *) parent NSLog (@ "% @ (% p) -% @", NSStringFromClass ((classe d'auto) ), self, NSStringFromSelector (_cmd));  - (void) didMoveToParentViewController: (UIViewController *) parent NSLog (@ "% @ (% p) -% @", NSStringFromClass ([self class]), self, NSStringFromSelector (_cmd));  - (void) viewWillAppear: (BOOL) animated [super viewWillAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([self class]), self, NSStringFromSelector (_cmd));  - (void) viewDidAppear: (BOOL) animated [super viewDidAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([self class]), self, NSStringFromSelector (_cmd));  - (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation durée: (NSTimeInterval) duration [super willRotateToInterfaceOrientation: toInterfacefaceOrientation duration: duration]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([self class]), self, NSStringFromSelector (_cmd));  - (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation [super didRotateFromInterfaceOrientation: fromInterfaceOrientation]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([self class]), self, NSStringFromSelector (_cmd));  @fin

Notre contrôleur de vue lui-même n’a rien de spécial, si ce n’est que nous avons ignoré les divers rappels afin que nous puissions les consigner chaque fois que notre ViewController l'instance devient un enfant pour notre contrôleur racine et une apparence ou un événement de rotation se produit.

Dans tout le code précédent, _cmd fait référence au sélecteur correspondant à la méthode selon laquelle notre exécution est à l'intérieur. NSStringFromSelector () le convertit en chaîne. C'est un moyen rapide et facile d'obtenir le nom de la méthode actuelle sans avoir à le taper manuellement.

Lançons un contrôleur de navigation et un contrôleur de tabulation dans le mix. Cette fois, nous allons utiliser les Storyboards.

Créer un nouveau fichier, et sous iOS> Interface utilisateur, choisir story-board. Définissez la famille d'appareils sur iPhone, et nommez-le NavStoryBoard.


Du bibliothèque d'objets, glisser et déposer un Contrôleur de navigation objet dans la toile. Glissez et déposez un élément de bouton de barre dans le côté gauche de la barre de navigation dans le contrôleur de vue de table désigné "Contrôleur de vue racine". Ceci contient la vue tabulaire de la toile. Donnez-lui un nom. Je l'ai nommée"La gauche"Son but est de vérifier le code que nous avons écrit pour que le bouton Cacher / Révéler de la barre de menus prenne sa place comme le bouton le plus à gauche de la barre de navigation, en poussant tous les boutons déjà présents vers la droite. Contrôleur de vue exemple et placez-le à la droite du contrôleur intitulé "Contrôleur de vue racine"dans la toile.

Cliquez là où il est écrit "Vue tableau"au centre du second contrôleur, et dans le inspecteur d'attributs changer le contenu de "Prototype dynamique" à "Cellules statiques".

Modification du type de contenu de cellule de dynamique à statique

Cela entraînera l'apparition de trois cellules de vue de table statique dans le générateur d'interface. Supprimer toutes les cellules de la vue tableau sauf une, tout en maintenant enfoncée Contrôle, cliquez et faites glisser de la cellule restante vers le contrôleur de vue à l'extrême droite, puis relâchez. Sélectionnez "pousser" sous Sélection Segue. Tout cela ne fait que provoquer une transition vers le contrôleur de vue de droite lorsque vous appuyez sur la cellule isolée de la vue Tableau. Si vous voulez, vous pouvez déposer un UILabel sur la cellule du tableau pour lui donner un texte. Votre story-board devrait ressembler à la photo ci-dessous.

NavStoryBoard

Enfin, ajoutons un contrôleur de barre d’onglet. Comme vous l’avez fait précédemment, créez un story-board déposer et appeler TabStoryBoard. Glissez et déposez un contrôleur de barre d'onglets article de la bibliothèque d'objets dans la toile. Il est préconfiguré avec deux onglets et, si vous le souhaitez, vous pouvez modifier la couleur d'arrière-plan des deux contrôleurs de vue à onglets en cliquant sur la vue correspondant à l'un ou l'autre des contrôleurs de vue et en modifiant le "Contexte"option dans le Inspecteur d'attributs. De cette façon, vous pouvez vérifier que la sélection du contrôleur de vue via l'onglet fonctionne correctement.

Votre story-board devrait ressembler à ceci.

4. Configuration du délégué de l'application

Maintenant il est temps de tout mettre en place dans le AppDéléguer.

Remplacez le code dans AppDelegate.m par le code suivant.

 #import "AppDelegate.h" #import "RootController.h" #import "ViewController.h" @implementation AppDelegate - (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.wind = alloc] initWithFrame: [[UIScreen mainScreen]]]; UIStoryboard * tabStoryBoard = [Ensemble de UIStoryboard storyboardWithName: @ "TabStoryboard": nil]; UIStoryboard * navStoryBoard = [Lot de UIStoryboard storyboardWithName: @ "NavStoryboard": nil]; UINavigationController * navController = [navStoryBoard instantiateViewControllerWithIdentifier: @ "Contrôleur de navigation"]; UITabBarController * tabController = [tabStoryBoard instantiateViewControllerWithIdentifier: @ "Contrôleur d'onglets"]; ViewController * redVC, * greenVC; redVC = [[ViewController alloc] init]; greenVC = [[ViewController alloc] init]; redVC.view.backgroundColor = [UIColor redColor]; greenVC.view.backgroundColor = [UIColor greenColor]; RootController * menuController = [[RootController alloc] initWithViewControllers: @ [tabController, redVC, greenVC, navController] andMenuTitles: @ [@ "Tab", @ "Rouge", @ "Vert", @ "Vert", @ "Nav"]]; self.window.rootViewController = menuController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; retourner OUI; 

Nous avons simplement créé des instances de ViewController et instancier le contrôleur de navigation et de tabulation à partir des deux story-boards. Nous les avons passés dans un tableau à notre RootControllerpar exemple. C'est le contrôleur de conteneur que nous avons mis en place au début. Nous l'avons fait avec un tableau de chaînes pour nommer les contrôleurs de vue dans le menu. Maintenant, nous allons simplement désigner notre instance de contrôleur racine initialisée comme étant celle de la fenêtre. rootViewController propriété.

Construisez et lancez l'application. Vous venez de mettre en œuvre le confinement des conteneurs! Appuyez sur les différentes cellules du tableau dans le menu pour remplacer la diapositive visible par la nouvelle glissière à partir de la droite. Remarquez comment, pour l'instance du contrôleur de navigation (nommée "NavC"dans le menu), le"La gauche"Le bouton a été déplacé d’un endroit vers la droite et le bouton de la barre de menu a été placé dans la position la plus à gauche. Vous pouvez modifier l’orientation en paysage et vérifier que tout semble correct..

Captures d'écran du simulateur

Conclusion

Dans ce didacticiel d'introduction, nous avons examiné la mise en œuvre d'iOS 6 dans le confinement du contrôleur de vue. Nous avons développé une version simple d'une interface d'application personnalisée qui a gagné en popularité et qui est souvent utilisée dans les applications très utilisées telles que Facebook et Path. Notre implémentation était aussi simple que possible, nous avons donc été en mesure de la disséquer facilement et de bien comprendre les bases. Il existe de nombreuses implémentations open-source sophistiquées de ce type de contrôleur que vous pouvez télécharger et étudier. Une recherche rapide sur Google JASidePAnels et SWRevealViewController, parmi d'autres.

Voici quelques idées sur lesquelles vous pouvez travailler.

  • Rendre l'implémentation plus flexible et l'API plus personnalisable.
  • Rendre l'interface plus jolie. Vous pouvez personnaliser l'apparence des cellules de la vue tableau ou laisser la vue de votre contrôleur de vue créer une ombre sur le menu pour donner une certaine profondeur à l'interface..
  • Faire en sorte que l'interface s'adapte mieux à l'orientation. Rappelez-vous que vos contrôleurs de vue enfant recevront des notifications de rotation, vous devez donc commencer!
  • Implémentez la reconnaissance des gestes de sorte que vous puissiez faire glisser un contrôleur de vue à gauche et à droite sur l'écran au lieu de cliquer sur le bouton du menu..
  • Concevez et développez un flux d'applications entièrement nouveau et novateur et réalisez l'interface utilisateur dans le code. Il est probable que vous aurez besoin d'utiliser le confinement du contrôleur de vue!

Une chose que je voudrais mentionner ici est qu’à partir de Xcode 4.5, il