RubyMotion - les onglets de navigation

Image non disponible Image non disponible

Dans cet article à propos de RubyMotion, nous allons voir comment mettre en place des onglets de navigation pour améliorer le confort utilisateur de notre application de Todo.

Nous allons améliorer notre application en proposant à l'utilisateur de naviguer comme bon lui semble grâce à un UITabBar bien plus convivial.

Vous pouvez récupérer le code de notre application sur GitHub et vous placer sur le commit « dd7a7bcebd » qui correspond à l'état dans lequel nous avons laissé l'application à la fin de l'article précédent.

Cet article est publié avec l'aimable autorisation de Synbioz, l'article original peut être lu sur le blog de Synbioz : RubyMotion - les onglets de navigation.

Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Création du contrôleur de navigation

Jusqu'ici, nous étions par défaut sur le contrôleur permettant l'ajout d'une tâche. Une fois la tâche ajoutée, nous étions automatiquement redirigés vers le contrôleur de liste des tâches. Depuis cette liste, une icône dans la barre d'entête nous permettait de revenir vers le formulaire.

La première chose à faire pour améliorer l'ergonomie est d'indiquer à notre application que nous voulons utiliser une navigation à base d'onglets plutôt que le système d'application à vue unique.

C'est donc le fichier app/app_delegate.rb qui va être concerné. Plutôt que d'instancier le TaskViewController et de le déclarer comme rootViewController, nous allons créer une méthode qui instancie un UITabBarController et définit ses différents onglets. C'est ensuite cette méthode qui sera utilisée pour définir le rootViewController :

 
Sélectionnez
class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    @window.rootViewController = appTabBarController
    @window.makeKeyAndVisible

    true
  end

  def appTabBarController
    tabBarController = UITabBarController.alloc.init
    tabBarController.viewControllers = [
      TaskViewController.alloc.init,
      UINavigationController.alloc.initWithRootViewController(ListViewController.alloc.initWithStyle(UITableViewStylePlain))
    ]
    tabBarController
  end
end

Le menu à onglet est en place et fonctionnel mais sans titre, ni icône :

Image non disponible

Modifions le code pour nommer nos onglets :

 
Sélectionnez
class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    @window.rootViewController = appTabBarController
    @window.makeKeyAndVisible

    true
  end

  def appTabBarController
    taskViewController = TaskViewController.alloc.init
    taskViewController.title = "Ajouter"

    listViewController = ListViewController.alloc.initWithStyle(UITableViewStylePlain)
    listViewController.title = "Tâches"

    tabBarController = UITabBarController.alloc.init
    tabBarController.viewControllers = [
      taskViewController,
      UINavigationController.alloc.initWithRootViewController(listViewController)
    ]

    tabBarController
  end
end

Comme vous pouvez le voir, pour résoudre notre problème, nous n'avons eu qu'à donner un titre à nos contrôleurs. Ce titre est utilisé automatiquement par les UITabBarItems.

Voici le résultat :

Image non disponible

Nous pourrions également définir des icônes pour chaque contrôleur via la propriété .tabBarItem.image mais nous ne le ferons pas ici.

Quelques problèmes entachent notre application suite à ces modifications :

  • la barre de navigation couvre partiellement notre bouton d'ajout de tâche ;
  • l'affichage de l'onglet « Tâches » fait apparaître un entête non-désiré généré par la UITabBarController ;
  • le bouton de validation de tâche fait planter l'application car elle utilise un système de transition incompatible avec le nouveau fonctionnement ;
  • depuis la liste des tâches, le bouton de retour à la liste ne fonctionne que partiellement (il affiche le bon contenu mais sans changer d'onglet).
Image non disponible

Corrigeons ces quelques problèmes.

II. Hauteur de barre de navigation

Pour corriger le problème de la barre de navigation qui couvre partiellement le bouton d'ajout de tâche, deux solutions s'offrent à nous. Nous pourrions simplement remonter le bouton ou alors réduire la hauteur de la barre de navigation.

Optons pour cette seconde solution qui nous permettra de découvrir de nouvelles choses.

Pour agir sur la position et la taille de la UITabBar, il faut redéfinir sa propriété frame. Nous allons donc la définir dans notre méthode appTabBarController du fichier app/app_delegate.rb juste après l'avoir instanciée :

 
Sélectionnez
def appTabBarController
  …

  tabBarController = UITabBarController.alloc.init
  tabBarController.tabBar.frame = [[0, UIScreen.mainScreen.bounds.size.height - 20], [UIScreen.mainScreen.bounds.size.width, 20]]end

On positionne donc la UITabBar sur le bord gauche de l'écran et à 20px de la bordure du bas. On définit la taille avec une largeur égale à celle de l'écran et une hauteur de 20px.

Voici ce que nous obtenons :

Image non disponible

III. Entête non-désiré

Deux problèmes existent sur l'onglet « Tâches ». Premièrement, la barre de statut d'iOS s'affiche. Il y a également l'entête auto-généré par le UITabBarController.

III-A. Masquer la barre de statut

Nous n'avons pas le souci avec notre contrôleur d'ajout de tâches car nous lui avons déjà demandé explicitement de masquer la barre de statut. Appliquons le même principe au contrôleur de liste des tâches.

Dans le fichier app/controllers/list_view_controller.rb, il faut ajouter la méthode suivante :

 
Sélectionnez
def prefersStatusBarHidden
  true
end

Je l'ajoute en ce qui me concerne dans les méthodes privées. Voici le résultat obtenu :

Image non disponible

III-B. Changer l'entête du UITabBarController

Il faut maintenant remplacer l'entête généré par le UITabBarController par notre entête personnalisé qui est actuellement affiché comme entête de notre tableau de tâches.

Commençons donc par supprimer les deux méthodes qui servent à la génération de cet entête dans notre tableau. Les deux méthodes concernées sont tableView:viewForHeaderInSection et tableView:heightForHeaderInSection:.

Notre tableau ne nous affiche donc plus que son contenu, sans entête :

Image non disponible

Nous devons changer l'entête par défaut, pour cela nous allons, dans le viewDidLoad, définir une image de fond pour la navigationBar puis changer son texte pour y mettre le titre de notre application :

 
Sélectionnez
def viewDidLoad
  self.navigationController.navigationBar.setBackgroundImage(UIImage.imageNamed("bgHeader.png"), forBarMetrics:UIBarMetricsDefault)

  self.navigationController.navigationBar.titleTextAttributes = {
    NSForegroundColorAttributeName => UIColor.colorWithRed(0.702, green: 0.702, blue: 0.702, alpha: 1.000),
    NSFontAttributeName => UIFont.fontWithName("AvenirNext-Bold", size: 25)
  }

  self.title = "RubyMotion Todo"
  self.navigationController.tabBarItem.title = "Tâches"
end

La première ligne nous permet d'utiliser notre image de fond. Ensuite nous définissons les attributs du texte de titre pour la navigationBar. Attention à bien utiliser les noms de classe comme clé, sinon cette ligne n'aura aucun effet. C'est pour cette raison que j'utilise l'ancienne syntaxe de Hash.

Les deux dernières lignes permettent de définir le titre. En changeant le title du contrôleur, la chaîne est mise à jour dans l'entête mais cette manipulation a pour effet de bord de redéfinir le titre du bouton d'onglet en bas. C'est pourquoi la dernière ligne redéfinit le titre de ce bouton.

Image non disponible

Il nous manque toujours le bouton de suppression d'une tâche. Nous ne remettrons pas le bouton de retour au formulaire puisque la navigation par onglet nous le permet.

Cet ajout est très simple puisqu'il consiste à ajouter le code suivant à la fin de la méthode viewDidLoad :

 
Sélectionnez
leftButtonItem = UIBarButtonItem.alloc.initWithCustomView(deleteButton)
self.navigationItem.setLeftBarButtonItem(leftButtonItem)

Les navigationBars sont prévus pour recevoir un bouton à gauche et à droite. Notre méthode générant le bouton existant déjà nous n'avions plus qu'à la réutiliser pour instancier un UIBarButtonItem et le placer à gauche.

Noter toutefois que j'ai légèrement réduit la taille du bouton pour qu'il s'intègre mieux visuellement :

Image non disponible

IV. Correction du bouton d'ajout de tâche

Notre bouton d'ajout de tâche pose un souci. Au moment de la transition du contrôleur d'ajout vers le contrôleur de liste des tâches, l'application plante car le contrôleur de liste initialisé ligne 18 de app/controllers/task_view_controller.rb n'est pas appelé dans le contexte attendu. Il n'intègre pas la notion de navigationController qui est requis dans notre nouveau mode de fonctionnement.

Il n'y a maintenant plus aucune raison d'initialiser ce contrôleur à cet endroit. En effet, il est déjà initialisé dans app/app_delegate.rb au chargement de l'application et intégré en tant que contrôleur lié au UITabBarController.

On peut donc retirer le code suivant de la méthode addTask :

 
Sélectionnez
@listViewController = ListViewController.alloc.initWithStyle(UITableViewStylePlain)
@listViewController.view.frame = self.view.frame

UIView.transitionFromView(self.view,
                          toView: @listViewController.view,
                          duration: 0.5,
                          options: UIViewAnimationOptionTransitionFlipFromLeft,
                          completion: nil)

Si vous testez à nouveau l'application, vous verrez que l'ajout de tâche fonctionne à nouveau. Il reste une chose à gérer : la transition automatique vers l'onglet de la liste des tâches. Nous retournons donc dans la méthode addTask pour ajouter le code suivant :

 
Sélectionnez
self.tabBarController.selectedIndex = 1

Cette ligne suffira à indiquer l'index de l'onglet souhaité et à l'afficher.

V. Conclusion

Nous avons pu mettre en place une navigation à base d'onglets, bien plus intuitive et flexible pour les utilisateurs.

Passer d'une application « single-page » à une application basée sur les onglets implique quelques changements dans la gestion, la logique et la présentation mais se fait finalement sans trop d'efforts.

L'utilisation des UITabBars est très courante dans les applications iOS, c'est donc un élément clé à maîtriser.

Cette simple modification donne plus de cachet à l'application et permet également d'étendre nos possibilités en tant que développeur. On évite également d'entasser les éléments de navigation dans le peu d'endroit qu'il nous reste à disposition dans notre interface.

Vous trouverez l'ensemble du code d'exemple de cet article, découpé en commits, sur GitHub.

VI. Remerciements

Cet article est publié avec l'aimable autorisation de Synbioz, l'article original peut être lu sur le blog de Synbioz : RubyMotion - les onglets de navigation.

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Synbioz. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.