Scriviamo un'app RubyMotion Parte 1

Cosa starai creando

RubyMotion è un framework che ti consente di creare applicazioni iOS in Ruby. Ti offre tutti i vantaggi del linguaggio Ruby, ma poiché il tuo codice è compilato in codice macchina, ottieni tutte le prestazioni non elaborate dello sviluppo in Objective-C. RubyMotion ti consente di utilizzare direttamente l'SDK di iOS, il che significa che puoi accedere a tutte le funzionalità più recenti della piattaforma. Puoi includere il codice Objective-C nel tuo progetto e RubyMotion funziona anche con CocoaPods.

In questo tutorial, costruirai un'applicazione per la pittura da zero. Ti mostrerò come incorporare Interface Builder nel tuo flusso di lavoro e come testare correttamente la tua applicazione. Se non hai precedenti esperienze su iOS o Ruby, ti consiglio di saperne di più su quelli per primi. I tutorial Tuts + Ruby for Newbies e Learning SDK per iOS da zero sono un ottimo punto di partenza.

Impostazione 1. Progetto

Prima di poter iniziare la codifica, è necessario che RubyMotion sia installato e configurato. Per i dettagli su come eseguire questa operazione, consultare la sezione Prerequisiti della guida introduttiva di RubyMotion.

Dopo averlo fatto, apri il tuo terminale e crea un nuovo progetto RubyMotion eseguendo:

movimento crea vernice vernice cd

Questo crea a dipingere directory e diversi file:

  • .gitignore: Questo file dice a Git quali file ignorare. Poiché RubyMotion genera file di build quando è in esecuzione, questo file è utile per mantenere i file di generazione generati fuori dal controllo del codice sorgente.
  • Gemfile: Questo file contiene le dipendenze dell'applicazione.
  • Rakefile: RubyMotion utilizza Rake per creare ed eseguire la tua applicazione. Il Rakefile configura la tua applicazione e carica le sue dipendenze. È possibile visualizzare tutte le attività disponibili per l'applicazione eseguendo rastrello -T dalla riga di comando.
  • app / app_delegate.rb: Il delegato dell'applicazione è il punto di accesso all'applicazione. Quando iOS completa il caricamento dell'applicazione in memoria, viene inviata una notifica al delegato dell'applicazione.

RubyMotion genera anche a spec / main_spec.rb file. Ti mostrerò come testare la tua applicazione un po 'più avanti in questo tutorial. Per ora, puoi cancellare questo file eseguendo rm spec / main_spec.rb dalla riga di comando.

Installa le dipendenze dell'applicazione eseguendo installazione bundle seguito da pacchetto rake exec per avviare la tua applicazione.

Woohoo! Uno schermo nero Lo renderà più interessante in un minuto.

2. Primo cambio

Anche se è bello avere un'app in esecuzione, uno schermo nero è un po 'noioso. Aggiungiamo un po 'di colore.

Come l'SDK iOS nativo, RubyMotion non ti obbliga a organizzare i tuoi file in alcun modo specifico. Tuttavia, è utile creare alcune cartelle nel file App directory per mantenere il tuo progetto organizzato. Eseguire i seguenti comandi dalla riga di comando per creare una directory per i modelli, le viste e i controller.

mkdir app / models mkdir app / views mkdir app / controller

Quindi, dai uno sguardo all'interno del app / app_delegate.rb file:

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

Se hai familiarità con lo sviluppo di iOS, noterai che questo metodo appartiene al UIApplicationDelegate protocollo, che fornisce diversi hook nel ciclo di vita dell'applicazione. Si noti che il AppDelegate la classe non dichiara che implementa il UIApplicationDelegate protocollo. Ruby si basa sulla digitazione anatra in quanto non supporta i protocolli. Ciò significa che non gli importa se la tua classe dice che implementa un protocollo, se ne importa solo se implementa i metodi corretti.

La definizione di applicazione: didFinishLaunchingWithOptions: metodo all'interno del AppDelegate la lezione potrebbe sembrare un po 'strana. In Objective-C, questo metodo dovrebbe essere scritto in questo modo:

- Applicazione (BOOL): l'applicazione (UIApplication *) ha fattoFinishLaunchingWithOptions: (NSDictionary *) launchOptions;

Poiché i nomi dei metodi Objective-C possono essere suddivisi in più parti, Ruby li implementa in un modo unico. La prima parte di applicazione: didFinishLaunchingWithOptions: è quello che sarebbe il nome del metodo nella risonanza magnetica. Il resto della firma del metodo è scritto come argomenti di parole chiave. In RubyMotion, applicazione: didFinishLaunchingWithOptions: è scritto così:

fine applicazione (applicazione, didFinishLaunchingWithOptions: launchOptions) 

Implementiamo questo metodo.

class AppDelegate def application (application, didFinishLaunchingWithOptions: launchOptions) @window = UIWindow.alloc.initWithFrame (UIScreen.mainScreen.bounds) @ ​​window.makeKeyAndVisible @ window.rootViewController = UIViewController.alloc.initWithNibName (nil, bundle: nil) true end end

Le prime due righe del applicazione: didFinishLaunchingWithOptions: metodo crea un nuovo oggetto finestra e lo rende la finestra chiave dell'applicazione. Perché è @finestra una variabile di istanza? RubyMotion raccoglierà i rifiuti dalla finestra a meno che non li archiviamo. L'ultima riga del metodo imposta il controller della vista radice della finestra su un nuovo controller di visualizzazione vuoto.

Esegui l'applicazione per fare in modo che tutto funzioni ancora.

Hmm. L'applicazione viene eseguita, ma lo schermo è ancora nero. Come sai che il tuo codice funziona? Puoi eseguire un rapido controllo di integrità aggiungendo quanto segue in fondo alla pagina applicazione: didFinishLaunchingWithOptions:, prima vero. Assicurati di rimuoverlo prima di andare avanti.

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

3. Test

Nessuna applicazione è completa senza una solida serie di test. I test consentono di essere sicuri che il codice funzioni e consente di apportare modifiche senza preoccuparsi di rompere il codice esistente.

RubyMotion viene fornito con una porta della libreria di test Bacon. Se hai familiarità con Rspec, Bacon si sentirà molto familiare.

Per iniziare, rispecchia il App struttura di directory nel spec directory eseguendo i seguenti comandi dalla riga di comando.

mkdir spec / models mkdir spec / views mkdir spec / controller

Quindi, crea il AppDelegateIl file delle specifiche di spec / app_delegate_spec.rb. Per convenzione, i file di origine sono specchi nella directory spec e hanno _spec aggiunto alla fine del nome del file.

Inizia questo corso definendo a descrivere blocco che dice al lettore che cosa sta testando il tuo file.

descrivere AppDelegate do end 

Successivamente, aggiungi un secondo descrivere blocco all'interno del primo per mostrare che si desidera testare il applicazione: didFinishLaunchingWithOptions: metodo.

descrivi AppDelegate descrivi "#application: didFinishLaunchingWithOptions:" fai end end

Hai notato il # all'inizio della firma del metodo? Per convenzione, i metodi di istanza iniziano con un hash e i metodi di classe iniziano con un punto.

Quindi, aggiungi una specifica usando un esso bloccare.

descrivi AppDelegate descrivi "#application: didFinishLaunchingWithOptions:" fai "crea la finestra" fai UIApplication.sharedApplication.windows.size.should == 1 end end end

Una delle cose migliori di Bacon e di altri framework di test BDD è che le specifiche sono molto chiare su ciò che stanno testando. In questo caso, ti stai assicurando che il applicazione: didFinishLaunchingWithOptions: metodo crea una finestra.

Le tue specifiche non devono chiamare il applicazione: didFinishLaunchingWithOptions: metodo direttamente. Si chiama automaticamente quando Bacon avvia la tua applicazione.

Esegui le specifiche della tua applicazione eseguendo bundle exec rake spec dalla riga di comando. Dovresti vedere un output come questo:

1 specifiche (1 requisiti), 0 guasti, 0 errori 

Questo ti dice che Bacon ha eseguito un test e non ha riscontrato errori. Se una delle tue specifiche fallisce, vedrai 1 fallimento e Bacon stamperà una descrizione dettagliata del problema.

Quanto sopra funziona, ma lo userete UIApplication.sharedApplication per tutte le tue specifiche Non sarebbe bello se potessi afferrare questo oggetto una volta e usarlo in tutte le specifiche? Puoi con a prima bloccare.

descrivi AppDelegate descrivi "#application: didFinishLaunchingWithOptions:" fai prima do @application = UIApplication.sharedApplication e "crea la finestra" do @ application.windows.size.should == 1 end end end

Ora puoi facilmente aggiungere il resto delle specifiche dell'applicazione.

descrivi AppDelegate descrivi "#application: didFinishLaunchingWithOptions:" fai prima do @application = UIApplication.sharedApplication e "crea la finestra" do @ application.windows.size.should == 1 termina "rende la chiave della finestra" do @application .windows.first.isKeyWindow.should.be.true fine "imposta il controller della vista radice" do @ application.windows.first.rootViewController.should.be.instance_of UIViewController end end end

Esegui questi per assicurarsi che tutto funzioni prima di proseguire.

4. Aggiunta dell'interfaccia utente

Esistono diversi modi per creare l'interfaccia utente usando RubyMotion. Il mio preferito è usare Interface Builder con la gemma IB. Apri il tuo Gemfile e aggiungi la gemma IB.

fonte 'https://rubygems.org' gemma 'rastrello' gemma 'ib'

Correre installazione bundle dalla riga di comando per installare la gemma. Se utilizzi Git, aggiungi ib.xcodeproj alla tua .gitignore file.

Interface Builder è una parte di Xcode. Avvia Interface Builder eseguendo bundle exec rake ib: aperto. Questo crea un progetto Xcode su misura per la tua applicazione. Creare un nuovo file di interfaccia utente selezionando Nuovo> File ... da Xcode's File menu e selezionare storyboard dal Interfaccia utente categoria a sinistra. Clic Il prossimo due volte per completare questo passaggio.

Salva lo storyboard in risorse directory come main.storyboard. Apri lo storyboard in Xcode e trascina un nuovo Visualizza controller in esso dal Libreria di oggetti sulla destra. Impostare il ID storyboard campo del controller a PaintingController.

Trascina un'etichetta nella vista del controller della vista da Libreria di oggetti a destra e imposta il suo testo a Ciao.

Quindi, apri app / app_delegatee sostituire l'ultima riga di applicazione: didFinishLaunchingWithOptions: con il seguente:

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

Quindi, eseguire nuovamente i test dell'applicazione con bundle exec rake spec per assicurarsi che passino ancora. Nota come non hai dovuto cambiarne nessuno? Le buone specifiche testano il comportamento del codice, non la sua implementazione. Ciò significa che dovresti essere in grado di cambiare Come il tuo codice è implementato e le tue specifiche dovrebbero ancora funzionare. Esegui la tua applicazione per testare la tua nuova interfaccia utente.

5. Pulsanti

Quello che hai costruito finora è grandioso, ma non sarebbe bello se la tua app avesse effettivamente fatto qualcosa? In questa sezione, aggiungerai i controlli per cambiare il colore del pennello. Crea due nuovi file, un controller e le sue specifiche, eseguendo i seguenti comandi.

touch app / controller / painting_controller.rb touch spec / controller / painting_controller_spec.rb

Implementare il PaintingControllerlo scheletro insieme alle sue specifiche.

classe PaintingController < UIViewController end
Descrivere PaintingController esegue i test di PaintingController,: storyboard => 'main',: id => 'PaintingController' fine

RubyMotion gestisce le specifiche del controller in un modo speciale. Il prova PaintingController,: storyboard => 'main',: id => 'PaintingController' linea del file spec dice a RubyMotion di usare il controller con un ID storyboard di PaintingController nel principale storyboard. Puoi usare il controllore variabile per testarlo.

Successivamente, dovrai aggiungere punti vendita al tuo controller. Questi ti permettono di connettere oggetti al tuo controller in 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

estendere IB aggiunge diversi metodi al controller, inclusi presa. Hai aggiunto cinque punti vendita, uno per ogni pulsante.

Le immagini per i pulsanti sono incluse nei file sorgente di questo tutorial. Scarica le immagini e copiali nel risorse directory. È necessario rigenerare il progetto Xcode per consentire a Interface Builder di raccogliere le modifiche apportate. Il modo più semplice per farlo è chiudendo Xcode ed eseguendo bundle exec rake ib: aperto, che riaprirà il progetto.

Seleziona il controller di visualizzazione e modifica la sua classe in PaintingController.

Aperto spec / app_delegate_spec.rb e modificare l'ultima specifica per verificare il PaintingController classe.

"imposta il controller della vista radice" do @ application.windows.first.rootViewController.should.be.instance_of PaintingController end

Aggiungi cinque pulsanti alla vista del controller della vista trascinando Pulsante oggetti sulla vista dal Libreria di oggetti sulla destra.

Questi pulsanti sono un po 'noiosi. Seleziona il primo pulsante, cambia il suo tipo in costume nel Ispettore degli attributi a destra e rimuovere il suo titolo. Assicurati di Predefinito lo stato è selezionato nel Stato Config menu a discesa e impostare l'immagine di sfondo su button_black.png. Impostare il Tinta proprietà del pulsante per trasparente.

Impostare il Stato Config menu a discesa a Selezionato e cambia l'immagine di sfondo in button_black_selected.png.

Nel Ispettore di taglia, cambia la larghezza e l'altezza del pulsante in 50.

Ripeti questa procedura per gli altri pulsanti.

Il prossimo passo è quello di agganciare i pulsanti alle prese del controller della vista che abbiamo dichiarato in precedenza. Tenere premuto il tasto Controllo tasto sulla tastiera e trascina dal controller della vista al primo pulsante. Quando si rilascia il mouse, viene visualizzato un menu. Selezionare black_button dal menu. Quindi, tieni premuto il tasto Controllo tasto e trascinare dal pulsante al controller della vista e scegliere il select_color metodo dal menu che si apre. Ripeti questi due passaggi per gli altri pulsanti.

Infine, seleziona il primo pulsante e fai clic su Selezionato checkbox sotto Controllo nel Ispettore degli attributi.

Ora è il momento giusto per aggiungere alcune specifiche utili a spec / painting_controller_spec.rb.

descrivere PaintingController esegue i test di PaintingController,: storyboard => 'main',: id => 'PaintingController' descrive "#black_button" do it "è connesso nello storyboard" do controller.black_button.should.not.be.nil end end descrive "#purple_button" fallo "è connesso nello storyboard" do controller.purple_button.should.not.be.nil end end descrive "#green_button" fallo "è connesso nello storyboard" do controller.green_button.should.not. be.nil end end descrive "#blue_button" do it "è connesso nello storyboard" do controller.blue_button.should.not.be.nil end end descrive "#white_button" do it "è connesso nello storyboard" do controller. white_button.should.not.be.nil end end end

Queste specifiche assicurano che le prese siano correttamente connesse in Interface Builder. Come sempre, è una buona idea eseguirli prima di procedere per assicurarsi che passino tutti.

Successivamente, implementerai il select_color metodo in PaintingController. Quando viene chiamato questo metodo, il pulsante che è stato toccato viene selezionato e il pulsante selezionato in precedenza viene deselezionato.

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

Aggiungi le specifiche a spec / controller / painting_controller_spec.rb.

descrivere "#select_color" prima di fare controller.select_color (controller.green_button) terminarlo "deseleziona gli altri colori" do controller.black_button.state.should == UIControlStateNormal controller.purple_button.state.should == UIControlStateNormal controller.blue_button.state .should == UIControlStateNormal controller.white_button.state.should == UIControlStateNormal termina "seleziona il colore" do controller.green_button.state.should == UIControlStateSelected end end 

Esegui l'applicazione e assicurati che la selezione dei pulsanti funzioni. Quando si tocca un pulsante, dovrebbe aumentare di dimensioni. Mentre questo è bello, ciò che si vuole veramente è che un colore venga selezionato quando si preme il pulsante. Questo è facile da realizzare con alcune aggiunte.

Sugarcube è un set di estensioni iOS per RubyMotion che rendono più semplici, come la creazione di colori, più semplici. Inserisci gemma 'sugarcube' al tuo Gemfile e corri installazione bundle. Quindi aggiungi richiedere "colorazione sugarcube" alla tua Rakefile sopra Movimento :: :: Progetto App.setup.

La gemma rende facile creare colori usando il loro codice esadecimale. Nel PaintingController class, aggiungi il seguente frammento di codice sotto la dichiarazione dei punti vendita:

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

Successivamente, refactoring la matrice di pulsanti in select_color in un metodo di supporto privato:

def pulsanti select_color (sender) .each do | button | button.selected = false end sender.selected = true @color = COLORS [sender.tag] end pulsanti def privati ​​[black_button, purple_button, green_button, blue_button, white_button] end 

Infine, aggiungi un nuovo metodo di seguito select_color che restituisce il colore selezionato.

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

Questo metodo acquisisce l'indice del pulsante selezionato e seleziona il colore corrispondente. Ovviamente, questo metodo non sarebbe completo senza test.

descrivere "#selected_color" prima di fare controller.select_color (controller.green_button) terminare "restituisce il colore corretto" do controller.selected_color.should == PaintingController :: COLORS [2] end end 

Esegui nuovamente la tua applicazione per assicurarti che tutto funzioni come previsto.

Conclusione

Hai coperto molto terreno in questo tutorial. Hai imparato come configurare ed eseguire un'applicazione RubyMotion, hai lavorato con Interface Builder e hai creato un'interfaccia utente.

Nella seconda parte di questo tutorial, approfondirai il modello Model-View-Controller su iOS e l'organizzazione della tua applicazione. Aggiungerai anche una vista pittura e scrivi il codice che consente all'utente di disegnare. Rimanete sintonizzati.