Écrivons une application RubyMotion Partie 1

Ce que vous allez créer

RubyMotion est un framework qui vous permet de créer des applications iOS en Ruby. Il vous offre tous les avantages du langage Ruby, mais comme votre code est compilé en code machine, vous bénéficiez de toutes les performances brutes du développement en Objective-C. RubyMotion vous permet d'utiliser le SDK iOS directement, ce qui signifie que vous avez accès à toutes les dernières fonctionnalités de la plate-forme. Vous pouvez inclure du code Objective-C dans votre projet et RubyMotion fonctionne même avec CocoaPods..

Dans ce tutoriel, vous allez créer une application de peinture à partir de zéro. Je vais vous montrer comment incorporer Interface Builder dans votre flux de travail et comment tester correctement votre application. Si vous n'avez aucune expérience préalable avec iOS ou Ruby, je vous recommanderais d'en apprendre plus sur celles-ci en premier. Les guides Tuts + Ruby for Newbies et Learning iOS SDK Development from Scratch constituent un excellent point de départ..

1. Configuration du projet

Avant de pouvoir commencer à coder, vous devez installer et configurer RubyMotion. Pour plus d'informations sur cette opération, consultez la section Prérequis du guide de démarrage de RubyMotion..

Cela fait, ouvrez votre terminal et créez un nouveau projet RubyMotion en lançant:

motion create paint cd paint

Cela crée un peindre répertoire et plusieurs fichiers:

  • .gitignore: Ce fichier indique à Git les fichiers à ignorer. RubyMotion générant des fichiers de construction lors de son exécution, ce fichier est utile pour garder vos fichiers de construction générés hors du contrôle du code source..
  • Gemfile: Ce fichier contient les dépendances de votre application.
  • Rakefile: RubyMotion utilise Rake pour créer et exécuter votre application. le Rakefile configure votre application et charge ses dépendances. Vous pouvez voir toutes les tâches disponibles pour votre application en lançant rake -T depuis la ligne de commande.
  • app / app_delegate.rb: Le délégué de l'application est le point d'entrée de votre application. Lorsque iOS finit de charger votre application en mémoire, le délégué de l'application est averti.

RubyMotion génère également un spec / main_spec.rb fichier. Je vais vous montrer comment tester votre application un peu plus tard dans ce tutoriel. Pour l'instant, vous pouvez supprimer ce fichier en exécutant rm spec / main_spec.rb depuis la ligne de commande.

Installez les dépendances de votre application en lançant installation groupée suivi par bundle exec rake pour commencer votre application.

Woohoo! Un écran noir Tu vas le rendre plus intéressant dans une minute.

2. Premier changement

Même s'il est agréable d'avoir une application en cours d'exécution, un écran noir est un peu ennuyeux. Ajoutons un peu de couleur.

Comme le SDK iOS natif, RubyMotion ne vous oblige pas à organiser vos fichiers de manière spécifique. Cependant, il est utile de créer quelques dossiers dans le répertoire. app répertoire pour garder votre projet organisé. Exécutez les commandes suivantes à partir de la ligne de commande pour créer un répertoire pour vos modèles, vues et contrôleurs..

mkdir app / modèles mkdir app / vues mkdir app / contrôleurs

Ensuite, jetez un oeil à l'intérieur du app / app_delegate.rb fichier:

Classe AppDelegate def application (application, didFinishLaunchingWithOptions: launchOptions) true end end

Si vous connaissez le développement iOS, vous remarquerez que cette méthode appartient à la UIApplicationDelegate protocole, qui fournit plusieurs points d'ancrage dans le cycle de vie de l'application. Notez que le AppDéléguer la classe ne déclare pas qu'elle implémente la UIApplicationDelegate protocole. Ruby s'appuie sur le dactylographie car il ne prend pas en charge les protocoles. Cela signifie qu'il ne s'inquiète pas de savoir si votre classe dit implémenter un protocole, cela ne le concerne que si elle implémente les méthodes correctes.

La définition de la application: didFinishLaunchingWithOptions: méthode à l'intérieur du AppDéléguer la classe peut sembler un peu étrange. En Objective-C, cette méthode s’écrirait comme ceci:

- (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions: (NSDictionary *) launchOptions;

Comme les noms de méthodes Objective-C peuvent être divisés en plusieurs parties, Ruby les implémente de manière unique. La première partie de application: didFinishLaunchingWithOptions: est ce que serait le nom de la méthode en IRM. Le reste de la signature de la méthode est écrit comme des arguments de mots clés. Dans RubyMotion, application: didFinishLaunchingWithOptions: est écrit comme ceci:

def application (application, didFinishLaunchingWithOptions: launchOptions) fin 

Implémentons cette méthode.

classe AppDelegate def application (application, didFinishLaunchingWithOptions: launchOptions) @window = UIWindow.alloc.initWithFrame (UIScreen.mainScreen.bounds) à l’aune du système

Les deux premières lignes du application: didFinishLaunchingWithOptions: method crée un nouvel objet window et en fait la fenêtre de clé de l'application. Pourquoi est-ce @la fenêtre une variable d'instance? RubyMotion va ramasser la fenêtre à moins que nous la stockions. La dernière ligne de la méthode définit le contrôleur de vue racine de la fenêtre sur un nouveau contrôleur de vue vide..

Exécutez l'application pour que tout fonctionne encore.

Hmm. L'application s'exécute mais l'écran est toujours noir. Comment savez-vous que votre code fonctionne? Vous pouvez effectuer un contrôle de santé rapide en ajoutant ce qui suit au bas de la application: didFinishLaunchingWithOptions:, avant vrai. Assurez-vous de l'enlever avant de passer à autre chose.

@ window.rootViewController.view.backgroundColor = UIColor.yellowColor

3. Test

Aucune application n'est complète sans une suite solide de tests. Les tests vous permettent de vous assurer que votre code fonctionne et vous permettent d'apporter des modifications sans craindre de casser le code existant..

RubyMotion est livré avec un port de la bibliothèque de tests Bacon. Si vous connaissez Rspec, Bacon se sentira très familier.

Pour commencer, reflétez le app structure de répertoire dans le spec répertoire en exécutant les commandes suivantes à partir de la ligne de commande.

mkdir spec / modèles mkdir spec / vues mkdir spec / contrôleurs

Ensuite, créez le AppDéléguerFichier de spécification de spec / app_delegate_spec.rb. Par convention, les fichiers source sont des miroirs dans le répertoire spec et ont _spec ajouté à la fin de leur nom de fichier.

Commencez cette classe en définissant un décrire bloc qui indique au lecteur ce que votre fichier teste.

décrire AppDelegate do end 

Ensuite, ajoutez une seconde décrire bloquer dans le premier pour montrer que vous voulez tester le application: didFinishLaunchingWithOptions: méthode.

décris AppDelegate décris "#application: didFinishLaunchingWithOptions:" do end end

Avez-vous remarqué le # au début de la signature de la méthode? Par convention, les méthodes d'instance commencent par un hachage et les méthodes de classe commencent par un point.

Ensuite, ajoutez une spécification en utilisant un il bloc.

décris AppDelegate décris "#application: didFinishLaunchingWithOptions:" fais-le "crée la fenêtre" do UIApplication.sharedApplication.windows.size.should == 1 end end end

Une des meilleures choses à propos de Bacon et des autres frameworks de test BDD est que les spécifications sont très claires sur ce qu’ils testent. Dans ce cas, vous vous assurez que le application: didFinishLaunchingWithOptions: méthode crée une fenêtre.

Votre spec n'a pas à appeler le application: didFinishLaunchingWithOptions: méthode directement. Cela s'appelle automatiquement lorsque Bacon lance votre application.

Exécutez les spécifications de votre application en exécutant bundle exec spécification à partir de la ligne de commande. Vous devriez voir la sortie comme ceci:

1 spécifications (1 exigences), 0 échecs, 0 erreurs 

Cela vous indique que Bacon a exécuté un test et n'a trouvé aucune erreur. Si l'une de vos spécifications échoue, vous verrez 1 échec et Bacon imprimera une description détaillée du problème.

Ce qui précède fonctionne, mais vous utiliserez UIApplication.sharedApplication pour toutes vos spécifications. Ce ne serait pas bien si vous pouviez saisir cet objet une fois et l'utiliser dans toutes les spécifications? Vous pouvez avec un avant bloc.

décris AppDelegate décris "#application: didFinishLaunchingWithOptions:" faire avant de faire @application = UIApplication.sharedApplication end it "crée la fenêtre" do @ application.windows.size.should == 1 end end end

Maintenant, vous pouvez facilement ajouter le reste des spécifications de l'application.

décris AppDelegate décris "#application: didFinishLaunchingWithOptions:" faire avant de faire @application = UIApplication.sharedApplication end it "crée la fenêtre" do @ application.windows.ssh.should == 1 end it "crée la fenêtre" do @application " .windows.first.isKeyWindow.should.be.true end it "définit le contrôleur de vue racine" do @ application.windows.first.rootViewController.should.be.instance_of de UIViewController

Exécutez-les pour vous assurer que tout fonctionne avant de continuer.

4. Ajout de l'interface utilisateur

Il existe plusieurs façons de créer l'interface utilisateur à l'aide de RubyMotion. Mon préféré est d'utiliser Interface Builder avec le bijou IB. Ouvrez votre Gemfile et ajoutez le joyau IB.

source 'https://rubygems.org' gem 'rake' gem 'ib'

Courir installation groupée à partir de la ligne de commande pour installer la gemme. Si vous utilisez Git, ajoutez ib.xcodeproj à ton .gitignore fichier.

Interface Builder fait partie de Xcode. Lancer Interface Builder en lançant bundle exec rake ib: ouvert. Cela crée un projet Xcode adapté à votre application. Créez un nouveau fichier d'interface utilisateur en sélectionnant Nouveau> Fichier… de Xcode Fichier menu et sélectionnez Storyboard du Interface utilisateur catégorie à gauche. Cliquez sur Suivant deux fois pour compléter cette étape.

Enregistrez le storyboard dans le Ressources répertoire en tant que tableau principal. Ouvrez le storyboard dans Xcode et faites glisser un nouveau Contrôleur de vue en dedans de la Bibliothèque d'objets sur la droite. Met le Identifiant de Storyboard champ du contrôleur à PeintureContrôleur.

Faites glisser une étiquette dans la vue du contrôleur de vue depuis le Bibliothèque d'objets à droite et mettre son texte à Bonjour.

Ensuite, ouvrez app / app_delegateet remplacez la dernière ligne de application: didFinishLaunchingWithOptions: avec ce qui suit:

storyboard = UIStoryboard.storyboardWithName ("main", bundle: nil) @ window.rootViewController = storyboard.instantiateInitialViewController

Ensuite, relancez les tests de votre application avec bundle exec spécification pour s'assurer qu'ils passent encore. Remarquez comment vous n'avez pas eu à en changer? Les bonnes spécifications testent le comportement du code, pas sa mise en œuvre. Cela signifie que vous devriez pouvoir changer Comment votre code est implémenté et vos spécifications devraient toujours fonctionner. Exécutez votre application pour tester votre nouvelle interface utilisateur.

5. boutons

Ce que vous avez construit jusqu'à présent est excellent, mais ne serait-il pas agréable si votre application a réellement fait quelque chose? Dans cette section, vous allez ajouter les commandes permettant de changer la couleur du pinceau. Créez deux nouveaux fichiers, un contrôleur et ses spécifications, en exécutant les commandes suivantes.

appuyez sur app / controllers / painting_controller.rb appuyez sur spec / controllers / painting_controller_spec.rb

Mettre en œuvre le PeintureContrôleursquelette avec sa spec.

classe PaintingController < UIViewController end
décrire PaintingController effectue des tests PaintingController,: storyboard => 'main',: id => 'PaintingController' end

RubyMotion traite les spécifications du contrôleur de manière particulière. le tests PaintingController,: storyboard => 'main',: id => 'PaintingController' la ligne du fichier de spécification indique à RubyMotion d’utiliser le contrôleur avec un ID de storyboard PeintureContrôleur dans le principale storyboard. Vous pouvez utiliser le manette variable pour le tester.

Ensuite, vous devrez ajouter des sorties à votre contrôleur. Celles-ci vous permettent de connecter des objets à votre contrôleur dans Interface Builder..

classe PaintingController < UIViewController extend IB outlet :black_button outlet :purple_button outlet :green_button outlet :blue_button outlet :white_button def select_color(sender) end end

étendre IB ajoute plusieurs méthodes à votre contrôleur, y compris sortie. Vous avez ajouté cinq sorties, une pour chaque bouton..

Les images des boutons sont incluses dans les fichiers source de ce didacticiel. Téléchargez les images et copiez-les dans le Ressources annuaire. Vous devez régénérer votre projet Xcode pour permettre à Interface Builder de prendre en compte les modifications apportées. Le moyen le plus simple de le faire est de fermer Xcode et d’exécuter bundle exec rake ib: ouvert, qui va rouvrir le projet.

Sélectionnez le contrôleur de vue et changez sa classe en PeintureContrôleur.

Ouvrir spec / app_delegate_spec.rb et modifier la dernière spécification pour vérifier la PeintureContrôleur classe.

il "définit le contrôleur de vue racine" do @ application.windows.first.rootViewController.should.be.instance_of PaintingController end

Ajoutez cinq boutons à la vue du contrôleur de vue en faisant glisser Bouton objets sur la vue depuis le Bibliothèque d'objets sur la droite.

Ces boutons sont un peu fades. Sélectionnez le premier bouton, changez son type en Douane dans le Inspecteur d'attributs à droite et supprimer son titre. Assurez-vous que Défaut l'état est sélectionné dans le Config d'état menu déroulant et définir l'image d'arrière-plan sur button_black.png. Met le Teinte propriété du bouton à transparent.

Met le Config d'état menu déroulant à Choisi et changez l’image d’arrière-plan en button_black_selected.png.

dans le Inspecteur de taille, changer la largeur et la hauteur du bouton en 50.

Répétez cette procédure pour les autres boutons.

L'étape suivante consiste à relier les boutons aux prises du contrôleur de vue que nous avons déclarées précédemment. Maintenez la Contrôle touche de votre clavier et faites glisser du contrôleur de vue vers le premier bouton. Un menu apparaîtra lorsque vous relâchez votre souris. Sélectionner black_button du menu. Ensuite, maintenez le Contrôle faites glisser la souris du bouton vers le contrôleur de vue et choisissez le sélectionnez la couleur méthode du menu qui apparaît. Répétez ces deux étapes pour les autres boutons.

Enfin, sélectionnez le premier bouton et cliquez sur le bouton Choisi case à cocher sous Contrôle dans le Inspecteur d'attributs.

Le moment est venu d'ajouter quelques spécifications utiles à spec / painting_controller_spec.rb.

décrire PaintingController fait des tests PaintingController,: storyboard => 'main',: id => 'PaintingController' décrire "#black_button" do it "est connecté au storyboard" faire controller.black_button.should.not.be.nil end end decrire "#purple_button" do it "est connecté au storyboard" do controller.purple_button.shot.not.be.nil end end decrire "#green_button" do it "est connecté au storyboard" do controller.green_button.should.not. be.nil end end décrire "#blue_button" do it "est connecté au storyboard" do controller.blue_button.shot.not.be.nil end end decrire "#white_button" do it "est connecté au storyboard" do controller. white_button.should.not.be.nil fin fin fin

Ces spécifications garantissent que les prises sont correctement connectées dans Interface Builder. Comme toujours, c'est une bonne idée de les exécuter avant de continuer pour s'assurer qu'ils réussissent tous..

Ensuite, vous allez implémenter le sélectionnez la couleur méthode en PeintureContrôleur. Lorsque cette méthode est appelée, le bouton tapé est sélectionné et le bouton précédemment sélectionné est désélectionné..

def select_color (expéditeur) [black_button, purple_button, green_button, blue_button, white_button] .each do | button | button.selected = false end expéditeur.selected = true end

Ajouter les spécifications à spec / controllers / painting_controller_spec.rb.

décrivent "#select_color" à faire avant de controller.select_color (controller.green_button) et de "désélectionne les autres couleurs" de controller.black_button.state.should == UIControlStateNormal controller.purple_button.state.should == UIControlStateNormal controller.blue_button.state .should == UIControlStateNormal controller.white_button.state.should == UIControlStateNormal end it "sélectionne la couleur" do controller.green_button.state.should == UIControlStateSelected end end 

Exécutez l'application et assurez-vous que la sélection du bouton fonctionne. Lorsque vous appuyez sur un bouton, sa taille devrait augmenter. Bien que ce soit cool, ce que vous voulez vraiment, c'est qu'une couleur soit sélectionnée lorsque vous appuyez sur le bouton. Ceci est facile à accomplir avec quelques ajouts.

Sugarcube est un ensemble d'extensions iOS pour RubyMotion qui simplifient plusieurs tâches, telles que la création de couleurs. Ajouter gem 'sucre' à votre Gemfile et courir installation groupée. Puis ajouter nécessite une "couleur sucre" à ton Rakefile au dessus de Motion :: Projet :: App.setup.

La gemme facilite la création de couleurs en utilisant leur code hexadécimal. dans le PeintureContrôleur classe, ajoutez l'extrait de code suivant sous la déclaration des points de vente:

COLORS = ["# 333333" .uicolor, "# 7059ac" .uicolor, "# 196e76" .uicolor, "# 80a9cc" .uicolor, "#fafafa" .uicolor] 

Ensuite, refactoriser le tableau de boutons dans sélectionnez la couleur dans une méthode d'aide privée:

def select_color (expéditeur) buttons.each do | button | button.selected = false et sender.selected = true @color = COLORS [sender.tag] et des boutons de définition privés [black_button, purple_button, green_button, blue_button, white_button] end 

Enfin, ajoutez une nouvelle méthode ci-dessous sélectionnez la couleur qui retourne la couleur sélectionnée.

def selected_color COLORS [buttons.find_index | button | button.state == UIControlStateSelected] end 

Cette méthode saisit l’index du bouton sélectionné et sélectionne la couleur qui lui correspond. Bien sûr, cette méthode ne serait pas complète sans tests.

decrire "#selected_color" faire avant de controller.select_color (controller.green_button) end it "retourne la couleur correcte" do controller.selected_color.should == PaintingController :: COLORS [2] end end 

Exécutez à nouveau votre application pour vous assurer que tout fonctionne comme prévu..

Conclusion

Vous avez couvert beaucoup de terrain dans ce tutoriel. Vous avez appris à configurer et à exécuter une application RubyMotion, vous avez travaillé avec Interface Builder et vous avez construit une interface utilisateur..

Dans la deuxième partie de ce didacticiel, vous allez approfondir le modèle Model-View-Controller sur iOS et l'organisation de votre application. Vous allez également ajouter une vue en peinture et écrire le code qui permet à l'utilisateur de dessiner. Restez à l'écoute.