Cet article est publié sous licence CC BY-NC-SA
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.
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é vers le contrôleur de liste des tâches. Depuis cette liste, une icône dans la barre d’en-tête nous permettait de revenir vers le formulaire.
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.
La première chose à faire pour cette évolution 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
:
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 :
Modifions le code pour nommer nos onglets :
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 UITabBarItem
s.
Voici le résultat :
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 :
UITabBarController
Corrigeons ces quelques problèmes.
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 deuxième 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 :
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 à 20 px de la bordure du bas. On définit la taille avec une largeur égale à celle de l’écran et une hauteur de 20 px.
Voici ce que nous obtenons :
Deux problèmes existent sur l’onglet “Tâches”. Premièrement, la barre de statut d’iOS s’affiche. Il y a également l’en-tête auto-générée par le UITabBarController
.
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 :
def prefersStatusBarHidden
true
end
Je l’ajoute en ce qui me concerne dans les méthodes privées. Voici le résultat obtenu :
Il faut maintenant remplacer l’en-tête générée par le UITabBarController
par notre en-tête personnalisée qui est actuellement affichée comme en-tête de notre tableau de tâches.
Commençons donc par supprimer les deux méthodes qui servent à la génération de cet en-tê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 en-tête :
Nous devons changer l’en-tê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 :
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 a 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’en-tête mais cette manipulation a pour effet de bord de redéfinir le titre du bouton d’onglet en bas. C’est donc pourquoi la dernière ligne redéfinie à nouveau le titre de ce bouton.
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
:
leftButtonItem = UIBarButtonItem.alloc.initWithCustomView(deleteButton)
self.navigationItem.setLeftBarButtonItem(leftButtonItem)
Les navigationBar
s 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 :
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 à cette 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
:
@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 :
self.tabBarController.selectedIndex = 1
Cette ligne suffira donc à indiquer l’index de l’onglet souhaité et à l’afficher.
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 UITabBar
s 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 cet article, découpé en commits sur GitHub.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.