I förra delen av 99mac:s artikelserie skapade vi en enkel app som fungerar – men den såg inte mycket ut för världen och hade en del skavanker. Nu ska du lära dig hur du lägger till bildresurser och knyter ihop säcken.
Det här är den fjärde och sista delen i 99mac:s serie om #IOS-utveckling för nybörjare. I förra delen gjorde vi en app som skapar en lista över dina Apple-prylar, men den var väldigt enkel och hade till exempel inte en enda bild, bara vita tomma ytor.
Dessutom kunde tangentbordet inte tas bort efter att det kommit fram, och datumväljaren hade klockslag vilket kanske inte är helt nödvändigt när du ska mata in när en pryl köptes.
Innan du kör igång den här delen rekommenderas att du läser föregående delar. Alternativt kan du fuska lite och ladda ner det färdiga projektet för del tre, och utgå från den – men om du inte redan är hyfsat välbekant med programmering för IOS kommer du säkerligen missa något och ha svårt att hänga med i vad vi faktiskt gör här.
En viktig sak att komma ihåg när det gäller programmering och hur det går till att lära sig är att kod som du kopierar rakt av inte lär dig ett skvatt. Det betyder inte att det aldrig är okej att kopiera kod, men det betyder att du inte kommer lära dig hur den fungerar och hur du kan anpassa den till dina egna projekt om du inte plockar isär den och ser hur den fungerar.
Det kan du antingen göra genom att läsa en guide som den här, slå upp saker du inte förstår och ställa frågor, eller genom att helt enkelt experimentera. Ta vår guide och koden du gjort här, men ändra saker. Testa att göra ett textfält för att mata in datumet istället för den UIDatePicker vi använde, eller efter den här guiden bygga om appen så att den använder ett rutnät av objekt (som i Bilder-applikationen i din Iphone) istället för en lista – då använder du något som heter Collection View Controller istället för Table View Controller.
Huvudsaken är att du ser till att förstå hur varje ny klass och metod du använder fungerar. Du behöver inte förstå hur den åstadkommer den funktionen, ibland går det inte ens. Apple visar inte koden bakom sina klasser, vad som faktiskt händer när du skickar [textField resignFirstResponder]; för att få ett textfält att sluta använda tangentbordet är omöjligt att veta. Istället menar vi att du måste förstå varför du ska skicka det här meddelandet.
Om du bara hade kopierat koden rakt av utan att titta på och försöka förstå vad de olika metoderna gör hade du lätt kunnat missa vad just resignFirstResponder gör, och om du nu medan du fortfarande har mycket att lära hela tiden gör sådana missar kommer du snart ha byggt upp ett stort batteri av luckor i ditt kunnande som du kanske inte vet att du har, men som kommer att göra det närmast omöjligt att få dina egna appar att fungera utan stor hjälp från utomstående.
Ta det lugnt med andra ord och lär dig de små grundbitarna metodiskt. Har du svårt att stå ut med det är det ett tydligt tecken på att utveckling förmodligen inte är din grej, för ”lugnt och metodiskt” är ledord hur avancerad du än blir och felsökning och rättelser av små, små fel och brister utgör en mycket större del av programmeringen än skrivandet av helt ny kod.
Med det ur vägen återgår vi till vår lilla Appleprylapp.
När du matar in en ny pryl i appen har du säkert märkt att tangentbordet aldrig försvinner. Vad vi behöver göra är att se till att textfältet slutar vara så kallad ”first responder”, vilket är IOS-snack för ett objekt som svarar först på inmatningar från användaren. Bara ett objekt kan vara first responder åt gången.
Ovan gav vi en föraning om hur du fixar detta och faktum är att du redan i förra avsnittet lade till koden som krävs. Problemet var bara att vi inte kopplade samman textfälten och vår AddNewViewController som vi precis hade gjort till UITextFieldDelegate och lagt till koden.
För att lösa det öppnar du din Storyboard och högerklickar och drar från vardera textfält till AddNewViewController i listan till vänster (se bild ovan). Nu fungerar returtangenten som den ska genom att avsluta inmatningen. Men borde det inte vara så att knappen heter Retur när du lägger till namnet och Done när du lägger till modellen, och borde den inte hoppa från namnet till modellen? Jo, och det fixar vi lätt genom att ändra lite i koden, så här:
- (BOOL)textFieldShouldReturn:(UITextField *)textField { if (textField == self.namnText) { [self.namnText resignFirstResponder]; [self.modellText becomeFirstResponder]; } else [textField resignFirstResponder]; return NO; }
Vad vi gör här är att kolla vilket textfält som tryckt på Retur, och om det var namnfältet byter vi helt enkelt till modellfältet. Är det modellfältet avslutar vi inmatningen. För att byta från Retur till Done som returknapp i modellfältet ändrar du i metoden viewDidLoad så här:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.modellText setReturnKeyType:UIReturnKeyDone]; [self.datum setMaximumDate:[NSDate date]]; }
Den andra raden vi lägger till fixar att datumväljaren inte kan passera dagens datum – det vore konstigt om du redan ägde en pryl med inköpsdatum i framtiden. Vill du ta bort klockslaget går du till din Storyboard, markerar datumväljaren och byter från Date and Time under Mode i dess inställningar (fjärde fliken som vanligt).
Nu ska vi fixa en bakgrund. Istället för att slösa utrymme med någon bildfil ska vi utnyttja IOS inbyggda grafikfunktioner för att skapa en övertoningseffekt. Tipset för detta kommer från utvecklaren Daniel Beard.
Välj File -> New -> File och välj Objectiv-C Class, döp den till XXXBackgroundLayer och sätt den som subclass till NSObject. Klicka sedan på själva projektet, allra längst upp till vänster, klicka på ditt Target (om det inte redan är markerat) och gå till fliken Build Phases.
Där hittar du en avdelning som heter Link Binary With Libraries. Öppna den, klicka på plusknappen och välj QuartzCore.framework.
Vad vi nu gjorde var att länka till ett av Apples alla ramverk, i det här fallet QuartzCore, vilket du ibland behöver göra när du ska använda resurser från andra ramverk. Ska du göra ett spel med Game Center måste du till exempel länka till GameKit.framework. Gå tillbaka till den nya klassens .h-fil och lägg till import av QuartzCore och en ny metod så att den ser ut så här:
#import <QuartzCore/QuartzCore.h> #import <Foundation/Foundation.h> @interface NNMBackgroundLayer : NSObject +(CAGradientLayer*) blueGradient; @end
Gå till .m-filen och skapa den nya metoden:
#import "NNMBackgroundLayer.h" @implementation NNMBackgroundLayer + (CAGradientLayer*) blueGradient { UIColor *colorOne = [UIColor colorWithRed:(120/255.0) green:(135/255.0) blue:(150/255.0) alpha:1.0]; UIColor *colorTwo = [UIColor colorWithRed:(57/255.0) green:(79/255.0) blue:(96/255.0) alpha:1.0]; NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil]; NSNumber *stopOne = [NSNumber numberWithFloat:0.0]; NSNumber *stopTwo = [NSNumber numberWithFloat:1.0]; NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil]; CAGradientLayer *headerLayer = [CAGradientLayer layer]; headerLayer.colors = colors; headerLayer.locations = locations; return headerLayer; } @end
Det här är egentligen lite väl komplicerat för den nivå vi ligger på i den här guiden, men i korthet går det ut på att skapa ett lager som är helt täckt av en övertoning mellan colorOne och colorTwo (som du kan ändra på om du vill, det är som du ser rgb-värden).
Du kan dessutom skapa en kopia till av metoden som du istället kallar till exempel grayBackground, och där du ändrar färgerna så att det blir en övertoning i grått istället. Metoden kallar du från en annan klass och den ger alltid ett färskt CAGradientLayer-objekt som svar, som du kan klistra in i ett annat objekt, som vi visar strax.
Gå till AddNewViewController.h och lägg till #import "NNMBackgroundLayer.h" längst upp vid de andra #import-raderna.
Gå nu till AddNewViewController.m och lägg till en ny metod:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CAGradientLayer *backgroundLayer = [NNMBackgroundLayer blueGradient]; backgroundLayer.frame = self.view.bounds; [self.view.layer insertSublayer:backgroundLayer atIndex:0]; }
viewWillAppear är en metod som körs varje gång en vy laddas, och det är ofta säkrare att göra ändringar av sådant som inte har fasta variabler här än i den liknande viewDidLoad-metoden. Varför det är så är aningen avancerat, men det har med minneshantering att göra.
Vad vi gör är att vi skapar ett nytt bakgrundslager med den metod vi nyss skrev, sätter storleken till hela ytan på AddNewViewController, och stoppar in det längst bak i vyn. Knappar, textfält och annat som vi har lagt till ovanpå kommer fortsätta ligga ovanför.
Testkör igen, appen bör nu se ut ungefär så här när du trycker på plusknappen för att lägga till en ny pryl.
Testa nu att själv lägga till en liknande bakgrund i DetailViewController och ändra dess etiketter till vita med skuggning också.
Tips: Importera XXXBackgroundLayer.h och titta på hur vi gjorde nyss.
Ray Wenderlich webbplats – Ray har skapat en hemsida som började som en bra källa till några nybörjarguider till spelmotorn Cocos2d men har utvecklats till en stor community för framför allt Cocos2d-utveckling, men även Cocoa Touch-utveckling och allt annat som rör IOS-programmering.
Tiotals guider för allt från totala nybörjare till veteraner som snabbt vill komma in i någon ny aspekt av IOS-utveckling och ett aktivt forum gör raywenderlich.com till ett självklart bokmärke.
Core Animation Programming Guide – Apples guide till Core Animation, det medialager som finns i både IOS och OS X som gör det enkelt att bland annat animera Cocoa Touch-vyer och att skapa sådant som det övertoningslager vi gjorde i den här guiden. PDF hos Apple.
Det mesta är förmodligen för avancerat för dig just nu, men det kan ändå vara intressant att läsa lite för att få ett hum om vilka möjligheter som finns.