Cum sa faci o carte cu sunete pentru iPad/iPhone folosind xCode si Objective-C

Tutorialul acesta necesită un Mac 10.8.2 și un xCode 4.5.2 - nu de alta, dar la cum schimbă Apple tehnologia nu mă miră mâine ce scriu eu aici să nu mai fie la zi.
Deschideți xCode si creați un nou proiect de iOS, folosind template-ul Page-Based Application:
Dați "Next" și dați-i un nume: (nu uitați să aveți bifata casuta de Devices:Universal)
Salvați proiectul local și testați-l dând click pe "Run":
După ce se compileaza o sa vedeți o aplicație tristă în care puteți da pagina, iar e fiecare pagina apara numele unei luni... "ianuarie, februarie, bla bla..." Dați "Stop" la execuția programului și importați in folderul curent resursele: imagini și sunete. Pozele vor avea nume "x.jpg" iar sunetele "x.mp3" unde x intre 1 si 12. Luați-le pur si simplu cu drag-and drop pe zona unde scrie numele proiectului, la importare bifați opțiunea de copiere locală:
... în final veți avea structura asta:
Acum, selectați "Build Phases - Link Binaries with Libraries" si adaugați librăria AVFoundation.framework apăsând pe "+":
Mutați librăria în folderul de frameworks pentru a avea structura asta:
Dacă după mutare veți vedea in Build Phases ca linia de AVFoundation.framework e scrisă cu roșu, selectați-o, apăsați "-" pentru a o șterge, apoi adăugați-o din nou. E o eroare de cale a xCode-ului pe care o veți rezolva astfel.
În structura de proiect dați click pe fișierul MainStoryboard_ipad.storyboard pentru a edita fisierul pentru iPad. Nu uitați la run să aveți selectată platforma de iPad pentru a testa. Apăsați pe semnul "=" pentru a da fit la pagină:
Selectați pagina "DataViewController - View" din meniul din stanga, apoi potriviți pagina cu zoom:
Având primul "View" selectat, cautați in dreapta jos itemul UIimageView
Luați-l cu drag'n drop și puneți-l în Data View Controller. Acum în stânga o să aveți structura:
În DataViewController.h importați headerul de la frameworkul AVFoundation, creați câteva variabile
în constructor, si o proprietate int. Pagina acum ar trebui sa arate cam asa:



#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface DataViewController : UIViewController{
IBOutlet UIImageView *poza; // aici va fi poza
AVAudioPlayer *playerSunet; // aici va fi sunetul
}

@property (strong, nonatomic) IBOutlet UILabel *dataLabel;
@property (strong, nonatomic) id dataObject;
@property int indexPagina;
@end

Acum, cel mai important este să legați obiectul UIImageView pe care l-ați pus în storyboard cu proprietatea "poza" declarata în DataViewController.h. Mergeți în MainStoryboard_ipad.storyboard și selectați "ImageView" din meniul din stânga. Apoi, în dreapta, dați click pe sageata aia mica, iar de sub "Referencig Outlets", în dreptul la "New Referencing Outlet" vedeți că e un punct. Dați click pe el, și fără a ridica mouse-ul, mergeți pe zona albastră din storyboard. Apoi ridicați mouse-ul, și alegeți proprietatea "poza".
E un procedeu dificil, și sigur vă întrebați de ce naibii trebuie un programator să facă drag'n drop ca să ruleze un program. Nu știu, considerați că pur și simplu treaba asta i se părea cool lui Steve Jobs.
Salvați și deschideți fișierul de implementare, DataViewController.m, unde adaugați metodele necesare pentru ca fisierul să arate cam așa:

#import "DataViewController.h"

@interface DataViewController ()
@end
@implementation DataViewController
- (void)dealloc{
[_dataLabel release];
[_dataObject release];
[super dealloc];
}

- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}


- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.dataLabel.text = [self.dataObject description];
//print ca metoda se apeleaza:
NSLog(@"VIEW WILL APPEAR_%u", [self indexPagina]);
//setam numele pozei in functie de indexul paginii
NSString *numePoza=[NSString stringWithFormat:@"%u.jpg", [self indexPagina]];
//facem un print ca sa ne asiguram ca merge:
NSLog(numePoza, @"este poza", self.dataLabel.text);
//cream o noua imagine
UIImage *img=[UIImage imageNamed:numePoza];
//punem imaginea in container:
[poza setImage:img];
}

-(void)viewDidAppear:(BOOL)animated{
int number=[self indexPagina];
//dupa ce apare view-ul cream numele sunetului in functie de indexul paginii:
NSString *soundName=[NSString stringWithFormat:@"%d", number];
//convertim numele sunetului in cale
NSString* path = [[NSBundle mainBundle] pathForResource:soundName ofType:@"mp3"];
//print calea catre sunet:
NSLog(@"osn %@ cale: %@", soundName, path);
NSURL *url=[NSURL fileURLWithPath:path];
//creeam o eroare pe care playerul sa o apleze daca sunt probleme:
NSError *error;
//cream instanta de player:
playerSunet=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
//setam de cate ori sa se repete sunetul, -1 e infinit, 0 e o data
playerSunet.numberOfLoops=-1;
//dam play la sunet
[playerSunet play];
}

-(void)viewDidDisappear:(BOOL)animated{
//oprim sunetul cand view-ul dispare
[playerSunet stop];
}

@end

Acum, dacă o sa testați o să vedeți că indexul de pagina nu se incrementeaza. Pentru asta, trebuie sa editați un pic fisierul ModelController.m Căutați linia

- (DataViewController *)viewControllerAtIndex:(NSUInteger)
iar înainte de
return dataViewController;
.. când obiectul este returnat, scrieți
dataViewController.indexPagina=index;
funcția o să arate cam așa:

- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard{
// Return the data view controller for the given index.
if (([self.pageData count] == 0) || (index >= [self.pageData count])) {
return nil;
}
// Create a new view controller and pass suitable data.
DataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:@"DataViewController"];
dataViewController.dataObject = self.pageData[index];
dataViewController.indexPagina=index;
return dataViewController;
}

Acum dacă testați o să vedeți că totul merge, dar când ajungeți la capăt, trebuie să o luați înapoi. Asta pentru că tot în ModelController.m, când indexul e prea mic sau prea mare, funcția returnează nil, în loc ca indexul să ia o nouă valoare. Asta e simplu de modificat: pur și simplu în loc de return nil scrieți ce valoare să ia indexul în situațiile respective. Sincer să fiu, eu n-am avut chef să mai stilizez nimic, iar la rulare, programelul arată cam așa:

Niciun comentariu:

Trimiteți un comentariu