Să scriem o aplicație RubyMotion Partea 1

Ce veți crea

RubyMotion este un cadru care vă permite să construiți aplicații iOS în Ruby. Vă oferă toate avantajele limbajului Ruby, dar pentru că codul dvs. este compilat cu codul mașinii, veți obține toate performanțele prime ale dezvoltării în Obiectiv-C. RubyMotion vă permite să utilizați direct SDK-ul iOS, ceea ce înseamnă că aveți acces la toate cele mai recente caracteristici ale platformei. Puteți include obiectivul C în proiectul dvs. și RubyMotion funcționează chiar și cu CocoaPods.

În acest tutorial, veți crea o aplicație de pictură de la zero. Vă voi arăta cum să încorporați Interface Builder în fluxul de lucru și cum să vă testați în mod corespunzător aplicația. Dacă nu aveți experiență anterioară iOS sau Ruby, aș recomanda să aflați mai multe despre aceștia în primul rând. Tuts + Ruby pentru începători și învățare Dezvoltarea iOS SDK de la ghidurile Scratch sunt un loc minunat pentru a începe.

Configurare 1. Proiect

Înainte de a putea începe codarea, trebuie să aveți RubyMotion instalat și configurat. Pentru detalii despre cum să faceți acest lucru, consultați secțiunea Prerequisites din ghidul de pornire RubyMotion.

Odată ce ați făcut acest lucru, deschideți terminalul și creați un nou proiect RubyMotion rulând:

mișcare crea vopsea cd vopsea

Aceasta creează o a picta director și mai multe fișiere:

  • .gitignore: Acest fișier îi spune lui Git ce fișiere să ignore. Deoarece RubyMotion generează fișiere de execuție atunci când rulează, acest fișier este util pentru păstrarea fișierelor de generare generate din controlul sursei.
  • Gemfile: Acest fișier conține dependențele aplicației dvs..
  • Rakefile: RubyMotion utilizează Rake pentru a construi și a rula aplicația. Rakefile configurează aplicația și încarcă dependențele. Puteți să vedeți toate sarcinile disponibile pentru aplicația dvs. executând rake -T din linia de comandă.
  • app / app_delegate.rb: Delegatul aplicației este punctul de intrare în aplicația dvs. Când iOS termină încărcarea aplicației în memorie, delegatul aplicației este notificat.

RubyMotion generează de asemenea a spec / main_spec.rb fişier. Vă voi arăta cum să vă testați aplicația mai târziu în acest tutorial. Deocamdată, puteți șterge acest fișier rulând rm spec / main_spec.rb din linia de comandă.

Instalați dependențele aplicației executând instalare pachet urmat de pachetul exec pentru a începe cererea.

Woo hoo! Un ecran negru. O să-l faci mai interesant într-un minut.

2. Prima schimbare

Chiar dacă este frumos să ai o aplicație care rulează, un ecran negru este puțin plictisitor. Să adăugăm o culoare mică.

Ca și SDK-ul nativ iOS, RubyMotion nu te forțează să-ți organizezi fișierele în mod specific. Cu toate acestea, este util să creați câțiva dosare în aplicaţia pentru a vă organiza proiectul. Rulați următoarele comenzi din linia de comandă pentru a crea un director pentru modele, vizualizări și controale.

mkdir app / modelele mkdir app / views mkdir app / controllers

Apoi, aruncă o privire înăuntru app / app_delegate.rb fişier:

clasă AppDelegate def (aplicație, didFinishLaunchingWithOptions: launchOptions) end end end

Dacă sunteți familiarizat cu dezvoltarea iOS, veți observa că această metodă aparține UIApplicationDelegate protocol, care oferă mai multe cârlige în ciclul de viață al aplicației. Rețineți că AppDelegate clasa nu declară că implementează UIApplicationDelegate protocol. Ruby se bazează pe tastarea rațelor, deoarece nu suportă protocoale. Aceasta înseamnă că nu-ți pasă dacă clasa ta spune că implementează un protocol, căci îi pasă doar dacă implementează metodele corecte.

Definiția aplicare: didFinishLaunchingWithOptions: în interiorul metodei AppDelegate clasa poate arăta puțin ciudat. În Obiectiv-C, această metodă va fi scrisă astfel:

- (BOOL): aplicație (UIApplication *) didFinishLaunchingWithOptions: (NSDictionary *) launchOptions;

Deoarece numele metodelor Obiectiv-C pot fi împărțite în mai multe părți, Ruby le implementează într-un mod unic. Prima parte din aplicare: didFinishLaunchingWithOptions: este ceea ce ar fi numele metodei în RMN. Restul semnăturii metodei este scrisă ca argumente ale cuvintelor cheie. În RubyMotion, aplicare: didFinishLaunchingWithOptions: este scris astfel:

def (aplicație, didFinishLaunchingWithOptions: launchOptions) sfârșit 

Să implementăm această metodă.

(aplicație, didFinishLaunchingWithOptions: launchOptions) @window = UIWindow.alloc.initWithFrame (UIScreen.mainScreen.bounds) @ ​​window.makeKeyAndVisible @ window.rootViewController = UIViewController.alloc.initWithNibName (zero, bundle: nil)

Primele două linii din aplicare: didFinishLaunchingWithOptions: metoda creează un obiect fereastră nouă și îl face fereastra cheie a aplicației. De ce este @fereastră o variabilă de instanță? RubyMotion va colecta gunoiul dacă nu îl stocăm. Ultimul rând al metodei stabilește controlerul de vizualizare rădăcină al ferestrei la un controler de vizualizare nou, gol.

Rulați aplicația pentru a face totul să funcționeze.

Hmm. Aplicația rulează, dar ecranul este încă negru. De unde știți că codul dvs. funcționează? Puteți face o verificare rapidă a sănătății adăugând următoarele în partea de jos a aplicare: didFinishLaunchingWithOptions:, inainte de Adevărat. Asigurați-vă că eliminați acest lucru înainte de a vă deplasa.

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

3. Testarea

Nici o aplicație nu este completă fără o serie solidă de teste. Testarea vă permite să vă asigurați că codul dvs. funcționează și vă permite să efectuați modificări fără să vă faceți griji despre ruperea codului existent.

RubyMotion se încarcă cu un port al bibliotecii de testare Bacon. Dacă sunteți familiarizat cu Rspec, Bacon se va simți foarte familiarizat.

Pentru a începe, oglindă aplicaţia structura directorului în spec director, executând următoarele comenzi din linia de comandă.

mkdir spec / modele mkdir spec / vizualizări mkdir spec / controllers

Apoi, creați AppDelegatefișierul de specificații la spec / app_delegate_spec.rb. Prin convenție, fișierele sursă sunt oglinzi în directorul spec și au _spec atașate la sfârșitul numelui fișierului.

Începeți această clasă prin definirea unui descrie bloc care îi spune cititorului ce testează fișierul tău.

descrieți AppDelegate până la sfârșit 

Apoi, adăugați o secundă descrie bloc în primul rând pentru a arăta că doriți să testați aplicare: didFinishLaunchingWithOptions: metodă.

descrieți AppDelegate descriu "#application: didFinishLaunchingWithOptions:" nu se termină

Ai observat # la începutul semnării metodei? Prin convenție, metodele instanței încep cu un hash și metodele de clasă încep cu o perioadă.

Apoi, adăugați o spec aceasta bloc.

descrieți AppDelegate descriu "#application: didFinishLaunchingWithOptions:" a face "creează fereastra" do UIApplication.sharedApplication.windows.size.should == 1 end end end

Unul dintre cele mai bune lucruri despre Bacon și alte cadre de testare BDD este că specificațiile sunt foarte clare despre ceea ce testează. În acest caz, vă asigurați că aplicare: didFinishLaunchingWithOptions: metoda creează o fereastră.

Spec-ul dvs. nu trebuie să apeleze aplicare: didFinishLaunchingWithOptions: metoda directă. Se numește automat când Bacon lansează aplicația.

Rulați specificațiile aplicației dvs. prin difuzare bundle exec rake spec din linia de comandă. Ar trebui să vedeți ieșirea astfel:

1 specificații (1 cerințe), 0 defecțiuni, 0 erori 

Acest lucru vă spune că Bacon a făcut un test și nu a găsit erori. Dacă unul din specificațiile dvs. nu reușește, veți vedea 1 eșec și Bacon va tipări o descriere detaliată a problemei.

Lucrările de mai sus, dar veți folosi UIApplication.sharedApplication pentru toate specificațiile. Nu ar fi bine dacă ați putea să luați acest obiect o dată și să-l utilizați în toate specificațiile? Poți cu a inainte de bloc.

descrieți AppDelegate nu descrie "#application: didFinishLaunchingWithOptions:" faceți înainte de a face @application = UIApplication.sharedApplication finalizează "creează fereastra" do @ application.windows.size.should == 1 end end end

Acum puteți adăuga cu ușurință restul specificațiilor aplicației.

descrieți AppDelegate descriu "#application: didFinishLaunchingWithOptions:" faceți înainte de a face @application = UIApplication.sharedApplication finalizează-l "creează fereastra" do @ application.windows.size.should == 1 termină "face cheia ferestrei" do @ appplication .windows.first.isKeyWindow.should.be.true termină "setează controlerul de vizualizare rădăcină" do @ application.windows.first.rootViewController.should.be.instance_of UIViewController end end end

Rulați-le pentru a vă asigura că funcționează înainte de a vă deplasa.

4. Adăugarea interfeței utilizator

Există mai multe moduri de a crea interfața cu utilizatorul folosind RubyMotion. Preferatul meu personal este de a folosi Interfață Builder cu bijuteria IB. Deschideți fișierul Gem și adăugați bijuteria IB.

sursă 'https://rubygems.org' gem 'rake' gem 'ib'

Alerga instalare pachet din linia de comandă pentru a instala bijuteria. Dacă utilizați Git, adăugați ib.xcodeproj pentru dumneavoastră .gitignore fişier.

Interfața Builder este o parte din Xcode. Lansați Interface Builder prin rulare pachetul exec rake ib: deschis. Acest lucru creează un proiect Xcode adaptat aplicației dvs. Creați un nou fișier de interfață utilizator selectând Nou> Fișier ... din Xcode Fişier meniu și selectați storyboard de la Interfața cu utilizatorul din stânga. Clic Următor → de două ori pentru a finaliza acest pas.

Salvați tabloul de bord în resurse directorul ca main.storyboard. Deschideți storyboard-ul în Xcode și trageți un nou Vizualizați controlerul în ea de la Biblioteca de obiecte pe dreapta. Seteaza Storyboard ID domeniul operatorului de la PaintingController.

Glisați o etichetă în vizualizarea controlerului de vizualizare din Biblioteca de obiecte din dreapta și setați textul la Salut.

Apoi, deschide-te app / app_delegateși înlocuiți ultima linie de aplicare: didFinishLaunchingWithOptions: cu urmatoarele:

storyboard = UIStoryboard.storyboardWithName ("principal", pachet: nil) @ window.rootViewController = storyboard.instantiateInitialViewController

Apoi, executați din nou testele aplicației bundle exec rake spec pentru a vă asigura că încă mai trec. Observați cum nu a trebuit să schimbați vreuna dintre ele? Specificațiile bune testează comportamentul codului, nu implementarea acestuia. Aceasta înseamnă că ar trebui să poți să te schimbi Cum codul dvs. este implementat și specificațiile dvs. ar trebui să funcționeze în continuare. Rulați aplicația pentru a testa noua interfață de utilizator.

5. Butoane

Ce ați construit până acum este mare, dar nu ar fi bine dacă aplicația dvs. a făcut ceva? În această secțiune, veți adăuga comenzile pentru comutarea culorii periei de vopsea. Creați două fișiere noi, un controler și specificațiile acestuia, executând următoarele comenzi.

touch app / controlere / painting_controller.rb touch spec / controllers / painting_controller_spec.rb

Implementați PaintingControllerschelet, împreună cu spec.

clasa PaintingController < UIViewController end
descrie PaintingController face testele PaintingController,: storyboard => 'main',: id => 'PaintingController' end

RubyMotion se ocupă de specificațiile controlerului într-un mod special. testele PaintingController,: storyboard => 'main',: id => 'PaintingController' linia din fișierul spec. îi spune lui RubyMotion să folosească controlerul cu un ID de storyboard PaintingController în principal storyboard. Puteți utiliza funcția controlor variabilă pentru a le testa.

Apoi, va trebui să adăugați puncte de vânzare controlorului dvs. Acestea vă permit să conectați obiecte la controlerul dvs. în Interface Builder.

clasa 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

extind IB adaugă mai multe metode la controlerul dvs., inclusiv priză. Ați adăugat cinci puncte de acces, câte unul pentru fiecare buton.

Imaginile pentru butoane sunt incluse în fișierele sursă ale acestui tutorial. Descărcați imaginile și copiați-le în resurse director. Trebuie să vă regenerați proiectul Xcode pentru ca Interface Builder să poată prelua modificările pe care le-am făcut. Cea mai ușoară modalitate de a face acest lucru este închiderea Xcode și rularea pachetul exec rake ib: deschis, care va redeschide proiectul.

Selectați controlerul de vizualizare și schimbați clasa lui PaintingController.

Deschis spec / app_delegate_spec.rb și modificați ultimul spec. pentru a verifica PaintingController clasă.

aceasta "stabilește controlerul de vizualizare rădăcină" face @ application.windows.first.rootViewController.should.be.instance_of PaintingController sfârșitul

Adăugați cinci butoane la vizualizarea controlerului de vizualizare prin glisare Buton obiecte pe vedere din Biblioteca de obiecte pe dreapta.

Aceste butoane sunt un pic plictisitoare. Selectați primul buton, modificați tipul acestuia Personalizat în Atribuții Inspector în dreapta și eliminați titlul. Asigurați-vă că Mod implicit stat este selectat în Config drop-down și setați imaginea de fundal la button_black.png. Seteaza Tentă proprietatea butonului să fie transparentă.

Seteaza Config drop-down meniu la Selectat și modificați imaginea de fundal la button_black_selected.png.

În Inspector de mărime, schimbați lățimea și înălțimea butonului 50.

Repetați acest proces pentru celelalte butoane.

Următorul pas este să cuplați butoanele până la prizele de la controlerul de vizualizare pe care le-am declarat anterior. Țineți apăsată tasta Control tasta de pe tastatură și trageți de la controlerul de vizualizare la primul buton. Va apărea un meniu când eliberați mouse-ul. Selectați black_button din meniu. Apoi, țineți apăsată tasta Control și trageți de la buton la controlerul de vizualizare și alegeți select_color din meniul care apare. Repetați acești doi pași pentru celelalte butoane.

În cele din urmă, selectați primul buton și faceți clic pe Selectat în caseta de selectare Control în Atribuții Inspector.

Acum este momentul potrivit pentru a adăuga câteva specificații utile spec / painting_controller_spec.rb.

descrie PaintingController face testele PaintingController,: storyboard => 'main',: id => 'PaintingController' descrie "#black_button" face "este conectat în storyboard" nu se descrie controller.black_button.should.not.be.nil "#purple_button" face "este conectat în storyboard" do controller.purple_button.should.not.be.nil sfârșitul final descrie "#green_button" face "este conectat în storyboard" do controller.green_button.should.not. be.nil capăt la capăt descrie "#blue_button" face "este conectat în storyboard" nu controler.blue_button.should.not.be.nil capăt capăt descrie "#white_button" face "este conectat în storyboard" a face controller. white_button.should.not.be.nil sfârșitul capătului final

Aceste specificații asigură că prizele sunt conectate corespunzător în Interface Builder. Ca întotdeauna, este o idee bună să le executați înainte de a vă asigura că toți trec.

Apoi, veți implementa select_color metoda în PaintingController. Când această metodă este apelată, butonul selectat este selectat și butonul selectat anterior este deselectat.

def select_color (expeditor) [buton alb, buton albastru, buton verde, buton albastru, buton alb]. button.selected = sfarsit false sender.selected = true end

Adăugați specificațiile pentru spec / controlere / painting_controller_spec.rb.

descrieți "#select_color" înainte de a face control.select_color (controller.green_button) terminați-l "deselectează celelalte culori" faceți controller.black_button.state.should == UIControlStateNormal controller.purple_button.state.should == UIControlStateNormal controller.blue_button.state .should == UIControlStateNormal controller.white_button.state.should == UIControlStateNormal sfârșitul "selectează culoarea" do controller.green_button.state.should == UIControlStateSelected end end 

Rulați aplicația și asigurați-vă că selecția butonului funcționează. Când atingeți un buton, ar trebui să crească în dimensiune. În timp ce acest lucru este rece, ceea ce doriți cu adevărat este pentru o culoare care trebuie selectată atunci când butonul este apăsat. Acest lucru este ușor de realizat cu câteva adăugiri.

Sugarcube este un set de extensii iOS pentru RubyMotion care fac mai multe sarcini, cum ar fi crearea de culori, mai simple. Adăuga gem "sugarcube" la Gemfile și să fugi instalare pachet. Apoi adauga necesită "sugarcube-color" pentru dumneavoastră Rakefile de mai sus Propunerea de proiect :: :: App.setup.

Gemul face ușor să creeze culori folosind codul hexagonal. În PaintingController class, adăugați următorul fragment de cod sub declarația de la punctele de vânzare:

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

Apoi, refactorul conține butoanele select_color într-o metodă de ajutor privat:

def select_color (expeditor) butoane button.selected = false final sender.selected = true @color = CULORI [sender.tag] finalizați butoanele private def [black_button, purple_button, green_button, blue_button, white_button] end 

În cele din urmă, adăugați o nouă metodă de mai jos select_color care returnează culoarea selectată.

def select_color CULORI [buttons.find_index | button | button.state == UIControlStateSelected] sfârșit 

Această metodă captează indexul butonului selectat și selectează culoarea care corespunde acestuia. Desigur, această metodă nu ar fi completă fără teste.

descrieți "#selected_color" înainte de a face control.select_color (controller.green_button) terminați-l "readuce culoarea corectă" do controller.selected_color.should == PaintingController :: COLORS [2] end end 

Rulați din nou aplicația pentru a vă asigura că totul funcționează conform așteptărilor.

Concluzie

Ați acoperit o mulțime de teren în acest tutorial. Ați învățat cum să configurați și să rulați o aplicație RubyMotion, ați lucrat cu Interface Builder și ați construit o interfață de utilizator.

În a doua parte a acestui tutorial, vă veți arunca mai adânc în modelul Model-View-Controller din iOS și din organizația aplicației dvs. De asemenea, adăugați o vizualizare de pictură și scrieți codul care permite utilizatorului să deseneze. Rămâneți aproape.

Cod