Programming iOS lezione 2

2,662 views
2,528 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,662
On SlideShare
0
From Embeds
0
Number of Embeds
630
Actions
Shares
0
Downloads
42
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Programming iOS lezione 2

  1. 1. LE TABLE VIEW
  2. 2. Cosa sono le Table View?Le table view sono gli elementi più comuniQuasi tutte le applicazioni di base di iPhone le usanoRendono facile la visualizzazione delle informazioniPossono essere di due tipi differenti: Plain Grouped
  3. 3. DettagliUna tabella è costituita da tre elementi: Una view Un’origine dati Un delegatoIniziamo dalla primaUna UITableView è una classe che presenta una tabella a video
  4. 4. Origine dati per una table viewUn’origine dati è un oggetto che descrive la relazione traUITableView e il suo contenutoGran parte delle funzioni sono svolte dal protocolloUITableViewDataSourceDispone di metodi per gestire l’inserimento, l’eliminazione el’ordinamento di righe nella tabellaI metodi richiesti sono tableView:numberOfRowsInSection: eTableView:cellForRowAtIndexPath:
  5. 5. DelegatoConsente all’applicazione host di avere maggior controllosull’aspetto e il comportamento della casellaRiceve notifiche per le varie azioni dell’utenteAltri metodi consentono al delegato di fornire viewpersonalizzate
  6. 6. Navighiamo nella tabellaCreiamo un nuovo progetto con Navigation Based ApplicationApriamo File->new Project in XcodeNon selezionare Use Core Data for StorageAssegnate al progetto MovieTable come nomeOra apriamo MainWindow.xib in IB e passiamo alla view adelencoIl progetto ha un navigation controller con una navigation bar
  7. 7. Dove si trova la tabella?Aprite RootViewController.xib, e vedrete il contenuto comesingolo oggetto UITableViewVediamo come dataSource e delegate sono connessi al F’sOPer tornare alla precedente astrazione vediamo come: RootViewController fa da delegato e origine dati La classe fornisce i metodi minimi per eseguire l’applicazione
  8. 8. Nota mnemonicaTenete sempre presente una cosa quando avete a che fare conTablesÈ SEMPRE necessario implementare le seguenti interfacce: UITableViewDataSource UITableViewDelgateRigorosamente da aggiungere all’@interface
  9. 9. Sviluppiamo il modello MVCPer il modello prendiamo la classe Movie della lezione primaIn group and files fare Ctrl+Click sulla classe e scegliere Add->Existing FilesNavigare fino al precedente progetto Movie e importare i duefiles .h e .mAssicurarsi di selezionare Copy Items into destination..
  10. 10. Modifiche al codice Aggiungete #import<Movie.h> al RootViewController.h Dichiarate la variabile istanza NSMutableArray moviesArray; Decommentiamo il metodo viewDidLoad in RootViewController.m e aggiungere il codice- (void)viewDidLoad { [super viewDidLoad]; moviesArray = [[NSMutableArray alloc] init]; Movie *aMovie = [[Movie alloc] init];! aMovie.title = @"Plaything Anecdote";! aMovie.boxOfficeGross = [NSNumber numberWithInt: 191796233];! aMovie.summary =! @"Did you ever think your dolls were really alive? Well, they are.";! [moviesArray addObject: aMovie];! [aMovie release];
  11. 11. Aggiornamento Aggiorniamo i nostri metodi per restituire la lunghezza dell’array- (NSInteger)tableView:(UITableView *)tableView! ! ! numberOfRowsInSection:(NSInteger)section {! return [moviesArray count];} Il codice precedente mostra che la tabella ha una sola riga Al momento dell’esecuzione verrà richiamato il metodo TableView:cellForRowAtIndexPath: Si otterrà quindi una UITableView per tale riga Per personalizzare la cella inserire il codice dopo il commento
  12. 12. NSIndexPathPerché usiamo NSIndexPath?È un oggetto che specifica un percorso attraverso una strutturaad alberoParte da un insieme di numeri interi che iniziano da zeroSu iPhone OS questa classe è estesa con proprietà specificheLa sezione e la riga son indicate come indexPath.{section,row}
  13. 13. Aggiunta del codice Quindi nel metodo di TableView:cellForRowAtIndexPath: aggiungeremo:Movie *aMovie = [moviesArray objectAtIndex:indexPath.row];cell.textLabel.text = aMovie.title;cell.detailTextLabel.text = aMovie.summary; La prima riga contiene il membro di moviesArray Nella seconda e terza presentiamo titolo e dettaglio del film
  14. 14. Proprietà della cellaLa cella di default ha tre proprietà principali textLabel detailTextLabel imageViewPer usare detailTextLabel dobbiamo usare uno stile differentedi cella
  15. 15. Stili di CellaEsistono quattro stili di cella differenti UITableViewCellStyleDefault (Testo con allineamento a Sx) UITableViewCellStyleSubtitle (Seconda riga con dettagli) UITableViewCellStyleValue1 (Dettagli a destra) UITableViewCellStyleValue2 (testo blu a Dx e dettagli a dx)
  16. 16. Riutilizzo delle celleNel metodo che stiamo utilizzando cellForRowAtIndexPath:esiste: l’inizializzatore per UITableViewCell: richiede la stringa: CellIdentifier: serve per recuperare la cella nel caso di scomparsa dallo schermo È una cache per il contenuto che non viene ricaricato Si reimposta il contenuto invece di creare nuove celle
  17. 17. Aggiungere la rimozioneÈ semplice e veloce scegliere dara la possibilità di rimuoverecelleBasta decommentare la funzionetableView:canEditRowAtIndexPath:Basta cambiare il valore di ritorno su YESPer la rimozione vera e propria invece è necessario utilizzaretableView:commitEditingStyle:forRowAtIndexPath:
  18. 18. Scriviamo il codiceCome al solito è tutto già implementatoDobbiamo solo supportare un pezzo di codiceIn questo caso UITableViewCellEditingStyleDeleteUI TableView fornisce già il metododeleteRowsAtIndexPaths:withRowsAnimation:Per il modello c’è removeObjectAtIndex:
  19. 19. Codice, codice, codice... - (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source. [moviesArray removeObjectAtIndex: indexPath.row]; [tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } }In questo modo otteniamo il classico comportamento trascinaper eliminareOra impostiamo anche il bottone di edit Decommentiamoself.navigationItem.leftBarButtonItem =self.editButtonItem; in ViewDidLoad:
  20. 20. Navigar m’è dolce..Nel capitolo precedente abbiamo usato una view modaleL’abbiamo presentata col metodo presentModalViewController:Ora la navigazione è gestita da UINavigationControllerDobbiamo prendere la classe MovieEditorViewControllerCopiamo le due classi e il file xib con la solita tecnicaSpostiamo lo xib nel gruppo Resources
  21. 21. Alcune ModificheVisto che precedentemente occupava tutto lo schermoOra la view va modificata con Simulated Interface Elements in IBImpostare Top Bar a Navigation BarCreiamo un IBOutlet in RootViewControllerAggiungiamo MovieEditorViewController *movieEditor; .... la property associata IBOutlet MEVC *movieEditor;
  22. 22. DettagliFacciamo @synthesize per questa proprietà nel file .mInseriamo #import "MovieEditorViewController.h" nell’headerCreiamone un’istanza in IBTrasciniamo UViewController dalla Lib in RootViewControllerCome identity impostiamo MovieEditorViewControllerConnettiamo movieEditor all’oggetto view controller
  23. 23. Modifica di un elemento tableView:DidSelectRowAtIndexPath: fornisce un template Questo crea una nuova view A noi non serve, useremo quella già fatta Modificheremo la classe nel seguente modo:- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here -- for example, create and push another view controller.! // AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];! // [self.navigationController pushViewController:anotherViewController animated:YES];! // [anotherViewController release];! editingMovie = [moviesArray objectAtIndex:indexPath.row];! movieEditor.movie = editingMovie;! [self.navigationController pushViewController:movieEditor animated:YES];}
  24. 24. Due commenti velociAbbiamo istanziato una variabile di tipo MovieQuesta memorizza il contenuto dell’ArrrayQuesto contenuto è poi passato al campo movie del VCLa proprietà navigationController è ereditata da RVCQuesta proprietà cerca all’interno della gerarchia fino a trovareun riferimento ad un UINavigationController
  25. 25. Il pulsante DonePer l’IBAction done: bisogna cambiare il comportamentoIn questo caso sarà necessario chiamare il popViewControllerCon la proprietà animated: settata a YES;Anche MEVC può accedere alla proprietà ereditata dalnavigationControllerOra il RVC ottiene il callback a viewWillAppear: e aggiorniamola view
  26. 26. viewWillAppear: - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated];! NSLog (@"viewWillAppear");! // update table view if a movie was edited! if (editingMovie) {! ! NSIndexPath *updatedPath = [NSIndexPath! ! ! indexPathForRow: [moviesArray indexOfObject: editingMovie] inSection: 0];! ! NSArray *updatedPaths = [NSArray arrayWithObject:updatedPath];! ! [self.tableView reloadRowsAtIndexPaths:updatedPaths withRowAnimation:NO];! ! editingMovie = nil;! }} Identifichiamo la fase di modifica Identifichiamo la riga di tabella aggiornata Otteniamo l’indice dell’arra y corrispondente a editingMovie Creiamo un NSIndexPath a quella riga e ricarichiamo la riga
  27. 27. Aggiungiamo un elemento Prima abbiamo usato leftBarButtonItem Ora per il pulsante Aggiungi definiamo una IBAction in RVC.h-(IBAction) handleAddTapped; In IB trascinare su RVC un UIBarButtonItem La connessione avviene in questo caso diversamente Il metodo selector viene richiamato sull’oggetto target L’oggetto target in questo caso è proprio il RVC
  28. 28. Implementiamo l’azione -(IBAction) handleAddTapped {! NSLog (@"handleAddTapped");! Movie *newMovie = [[Movie alloc] init];! [moviesArray addObject: newMovie];! editingMovie = newMovie;! movieEditor.movie = editingMovie;! [self.navigationController pushViewController:movieEditor animated:YES];! // update UITableView (in background) with new member! NSIndexPath *newMoviePath = [NSIndexPath indexPathForRow: [moviesArray count]-1 inSection:0];! NSArray *newMoviePaths = [NSArray arrayWithObject:newMoviePath];! [self.tableView insertRowsAtIndexPaths:newMoviePaths withRowAnimation:NO];}
  29. 29. LA NAVIGAZIONE
  30. 30. Come funziona la navigazioneC’è un Navigation ControllerLa navigazione è organizzata con uno stackTipicamente si parte da RootViewControllerSi passa ad una serie più o meno infinita di altri VCOgnuno riporta un titolo ed un link al precedenteSi passa dal generale al particolare
  31. 31. Esaminiamo le coseApriamo un nuovo progetto chiamato DVDCaseAndiamo a vedere MainWindow.xibEsaminiamo il Navigation controllerTroviamo finalmente la Table ViewNotiamo che sia dataSource che delegate sono del File’s Owner
  32. 32. Piccole modifiche Sono implementati i metodi numberOfRowInSection: e cellForRowAtIndexPath: li modifichiamo leggermente:- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // return 0;! return 2;} In questo caso abbiamo solo due sezioni
  33. 33. Comportamento del VC Invece modifichiamo alcune righe - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) {! cell = [[[UITableViewCell alloc] initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier]! ! autorelease]; } cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; switch (indexPath.row) { case 0: cell.textLabel.text = @"Home"; break; case 1: cell.textLabel.text = @"Work"; break; default: break; } return cell;}
  34. 34. Altre modifiche Andiamo a implementare didSelectRowAtIndexPath:- (void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath { if(0 == indexPath.row) { self.cabinetController.key = @"home"; self.cabinetController.title = @"Home"; } else { self.cabinetController.key = @"work"; self.cabinetController.title = @"Work"; } [self.navigationController pushViewController:self.cabinetController animated:YES];} Impostiamo il titolo in maniera condizionale Creeremo anche il VC CabinetController
  35. 35. PrecisazioniAbbiamo impostato il titolo del VC in maniera condizionaleLa chiamata a pushViewController rende attiva la view del VCLa proprietà cabinetController va dichiarata al RVCAggiungiamo una variabile istanza e un’istruzione @synthesizeModifichiamo viewDidLoad: per visualizzare il testo nel pulsante
  36. 36. Personalizzazione - (void)viewDidLoad { [super viewDidLoad];! self.title = @"Cases";} Ora creiamo il VC cabinetController Vedremo che è possibile personalizzare qualcosa in più Possiamo aggiungere un bottone a sx Istanza personalizzata di UIBarButtonItem Con customView si potrebbe sostituire del tutto la view
  37. 37. Creiamo il nuovo VCCreiamo una sottoclasse di UITableViewControllerCreiamo il nuovo file NIB che contiene l’interfaccia utenteConfigurare il file NIB per avere una TV e al nostro VCAggiungere un outlet in RVC per farle conoscere il nuovo VCAggiornare RVC.xib per impostare questo outlet
  38. 38. Aggiungiamo quello che serve Aggiungiamo un file sottoclasse di UITableViewController Chiamiamola DVDCabinetController Aggiungiamo il nuovo outlet a RVC, aggiungiamo import e synth@class DVDCabinetController;@interface RootViewController : UITableViewController {! DVDCabinetController *cabinetController;}@property(nonatomic, retain) IBOutlet DVDCabinetController *cabinetController;@end
  39. 39. ModifichePer connettere l’outlet, apriamo RVC.xib e aggiungiamo un VCImpostare la classe DVDCabinetController nella finestraIdentityConnettere il File’s Owner all’outlet cabinetControllerCreiamo una nuova View da Add->New File, View XIBSostituiamo la UIView con una UITableViewImpostiamo come classe dell’oggetto File’s Owner DVDCC
  40. 40. Connettiamo gli oggettiCreiamo le connessioni necessarieTrasciniamo dall’outlet view del F’sO al nuovo oggettoTableViewScegliere l’outlet viewConnettere dataSource e delegate al File’s OwnerPer visualizzare i dati è necessario implementare i soliti 2 metodi
  41. 41. Implementiamo Nel file DVDCabinetController.h@interface DVDCabinetController : UITableViewCell {! NSDictionary *data;! NSString *key;}@property (nonatomic, retain) NSString *key; Nel file DVDCabinetController.m-(void)viewDidLoad {! [super viewDidLoad];! NSArray *keys = [NSArray arrayWithObjects:@"Home",@"Work", nil];! NSArray *homeDVDs = [NSArray arrayWithObjects:@"Thomas the Builder", nil];! NSArray *workDVDs = [NSArray arrayWithObjects:@"Intro to Blender",nil];! NSArray *values = [NSArray arrayWithObjects:homeDVDs, workDVDs, nil];! data = [[[NSDictionary alloc] initWithObjects: values forKeys: keys];!}
  42. 42. Ultimi ritocchiAbbiamo fatto due dizionari per contenere i valori memorizzatiin RVCTipicamente non si usa questo tipo di approccioRisulta però così più leggibile il codiceModifichiamo i metodi per il ritorno del numero di valoriE personalizziamo la cella affinché mostri il valore corretto
  43. 43. Ancora modifiche - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return [[data valueForKey:self.key]count];}// Customize the appearance of table view cells.- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } // Configure the cell...! cell.textLabel.text = [[data valueForKey:self.key] objectAtIndex:indexPath.row];! return cell;}
  44. 44. Ultima porzione di codice Finiamo due modifiche per viewWillAppear:- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated];! [self.tableView reloadData];} E tableView:didSelectRowAtIndexPath:- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here. Create and push another view controller.! [self.navigationController popViewControllerAnimated:YES];} Finalmente torniamo indietro nella navigazione tramite il riferimento al NavigationController
  45. 45. MAPKIT
  46. 46. Cosa fa MapKitÈ la classe che si occupa della generazione di mappeÈ particolarmente utile in virtù della localizzazione del deviceUnendo le due funzionalità si possono ottenere ottimi risultatiLa nostra piccola applicazione centrerà la mappa sulla nostraposizione corrente
  47. 47. Primo passoCome prima cosa è necessario aggiungere al progetto iFrameworkCreiamo un nuovo progetto e chiamiamolo FindMeUtilizziamo il template View-Based ApplicationAggiungiamo i Framework MapKit e CoreLocationApriamo il file NIB e trascinate un MapView
  48. 48. Quasi finitoAbbiamo quasi finito, basta selezionare Show User LocationSelezioniamo il tipo di mappa (Map)Salviamo e eseguiamoIl simulatore mostrerà una posizione fittizia sull’Apple CampusOra vogliamo che la mappa venga centrata nuovamente eingrandita
  49. 49. Centrare le mappePer centrare le mappe bisogna usare il metodo setRegion:Il parametro region: è una struttura C simile a CGRectMKCoordinateRegion ha due parti center e span.centerIl primo è un CLocationCoordinate2D con coordinate del puntoIl secondo è un MKCoordinateSpan e specifica la variazione ingradi delle coordinate della regione da includereCentriamo la mappa con .15 di differenza tra le due misure
  50. 50. Codice per centrare le mappe - (void)setCurrentLocation:(CLLocation *)location { MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}}; region.center = location.coordinate; region.span.longitudeDelta = 0.15f; region.span.latitudeDelta = 0.15f; [self.mapView setRegion:region animated:YES];} Il Codice è abbastanza autoesplicativo, settiamo la regione Prendiamo le coordinate della nostra posizione Impostiamo anche lo span Diciamo alla mappa di settarsi con un’animazione Impostiamo anche un IBOutlet nel codice per MKView
  51. 51. Aggiungere annotazioniInseriamo MKMapView *_mapView; nel file .h,Chiamiamo l’IBOutlet nella stessa manieraE poi sintetizziamo dicendo che _mapView = mapView;Teoricamente dovremo vedere anche il delegato del localizzatoreIn realtà Show User Location farà il lavoro per noiPer le annotazioni MKAnnotation non definisce leimplementazioni pubbliche
  52. 52. Le annotazioniPer aggiungere un’annotazione dobbiamo creare la nostraspecifica implementazione di questo protocolloIl protocollo definisce una proprietà e due metodi opzionaliLa proprietà è la localizzazione dell’annotazioneI metodi sono title e subtitleVengono presentati sull’annotazione entrambiUno il titolo, uno il sottotitolo
  53. 53. Creiamo un modello Creiamo una classe che implementa <MKAnnotation>#import <Foundation/Foundation.h>#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>@interface ContactAnnotation : NSObject <MKAnnotation> { CLLocationCoordinate2D _coordinate; NSString *_title; NSString *_subtitle;}+ (id)annotationWithCoordinate:(CLLocationCoordinate2D)coordinate;- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;@property (nonatomic, assign) CLLocationCoordinate2D coordinate;@property (nonatomic, copy) NSString *title;@property (nonatomic, copy) NSString *subtitle;@end Abbiamo definito il nostro protocollo, ora tocca alle classi
  54. 54. Il file d’implementazione Andiamo a implementare il protocollo nel nostro file:#import "ContactAnnotation.h"@implementation ContactAnnotation@synthesize coordinate = _coordinate;@synthesize title = _title;@synthesize subtitle = _subtitle;+ (id)annotationWithCoordinate:(CLLocationCoordinate2D)coordinate { return [[[[self class] alloc] initWithCoordinate:coordinate] autorelease];}- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate { self = [super init]; if(nil != self) { self.coordinate = coordinate; } return self;}@end
  55. 55. Aggiungere un’azione Teoricamente potremmo decidere di scatenare un’azione alla pressione del tasto Definiamo l’IBAction choose: come segue- (IBAction)choose { UINavigationController *detailView = [[UINavigationController alloc] init]; detailView.viewDelegate = self; [self presentModalViewController:detailView animated:YES]; [detailView release];} Aggiungiamo la definizione nel file header e creiamo la connessione al File’s Owner
  56. 56. Aggiungiamo la nota alla mappaNel metodo viewDidApper: possiamo inserire l’animazionePossiamo inserire la nostra istanza di ContactAnnotationIstanziamo la classe da qualche parte nel codice dove più ci serveself.newAnnotation= [ContactAnnotationannotationWithCoordinate:coordinate];Chiamiamo il metodo d’inserimento con [self.mapViewaddAnnotation:sel.newAnnotation];
  57. 57. ALLA PROSSIMA LEZIONE!

×