2. Cosa sono le Table View?
Le table view sono gli elementi pi湛 comuni
Quasi tutte le applicazioni di base di iPhone le usano
Rendono facile la visualizzazione delle informazioni
Possono essere di due tipi differenti:
Plain
Grouped
3. Dettagli
Una tabella 竪 costituita da tre elementi:
Una view
Unorigine dati
Un delegato
Iniziamo dalla prima
Una UITableView 竪 una classe che presenta una tabella a video
4. Origine dati per una table view
Unorigine dati 竪 un oggetto che descrive la relazione tra
UITableView e il suo contenuto
Gran parte delle funzioni sono svolte dal protocollo
UITableViewDataSource
Dispone di metodi per gestire linserimento, leliminazione e
lordinamento di righe nella tabella
I metodi richiesti sono tableView:numberOfRowsInSection: e
TableView:cellForRowAtIndexPath:
5. Delegato
Consente allapplicazione host di avere maggior controllo
sullaspetto e il comportamento della casella
Riceve notifiche per le varie azioni dellutente
Altri metodi consentono al delegato di fornire view
personalizzate
6. Navighiamo nella tabella
Creiamo un nuovo progetto con Navigation Based Application
Apriamo File->new Project in Xcode
Non selezionare Use Core Data for Storage
Assegnate al progetto MovieTable come nome
Ora apriamo MainWindow.xib in IB e passiamo alla view ad
elenco
Il progetto ha un navigation controller con una navigation bar
7. Dove si trova la tabella?
Aprite RootViewController.xib, e vedrete il contenuto come
singolo oggetto UITableView
Vediamo come dataSource e delegate sono connessi al FsO
Per tornare alla precedente astrazione vediamo come:
RootViewController fa da delegato e origine dati
La classe fornisce i metodi minimi per eseguire lapplicazione
8. Nota mnemonica
Tenete sempre presente una cosa quando avete a che fare con
Tables
SEMPRE necessario implementare le seguenti interfacce:
UITableViewDataSource
UITableViewDelgate
Rigorosamente da aggiungere all@interface
9. Sviluppiamo il modello MVC
Per il modello prendiamo la classe Movie della lezione prima
In group and files fare Ctrl+Click sulla classe e scegliere Add-
>Existing Files
Navigare fino al precedente progetto Movie e importare i due
files .h e .m
Assicurarsi di selezionare Copy Items into destination..
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. Aggiornamento
Aggiorniamo i nostri metodi per restituire la lunghezza dellarray
- (NSInteger)tableView:(UITableView *)tableView
! ! ! numberOfRowsInSection:(NSInteger)section {
! return [moviesArray count];
}
Il codice precedente mostra che la tabella ha una sola riga
Al momento dellesecuzione 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. NSIndexPath
Perch辿 usiamo NSIndexPath?
un oggetto che specifica un percorso attraverso una struttura
ad albero
Parte da un insieme di numeri interi che iniziano da zero
Su iPhone OS questa classe 竪 estesa con propriet specifiche
La sezione e la riga son indicate come indexPath.{section,row}
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. Propriet della cella
La cella di default ha tre propriet principali
textLabel
detailTextLabel
imageView
Per usare detailTextLabel dobbiamo usare uno stile differente
di cella
15. Stili di Cella
Esistono 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. Riutilizzo delle celle
Nel metodo che stiamo utilizzando cellForRowAtIndexPath:
esiste:
linizializzatore 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. Aggiungere la rimozione
semplice e veloce scegliere dara la possibilit di rimuovere
celle
Basta decommentare la funzione
tableView:canEditRowAtIndexPath:
Basta cambiare il valore di ritorno su YES
Per la rimozione vera e propria invece 竪 necessario utilizzare
tableView:commitEditingStyle:forRowAtIndexPath:
18. Scriviamo il codice
Come al solito 竪 tutto gi implementato
Dobbiamo solo supportare un pezzo di codice
In questo caso UITableViewCellEditingStyleDelete
UI TableView fornisce gi il metodo
deleteRowsAtIndexPaths:withRowsAnimation:
Per il modello c竪 removeObjectAtIndex:
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 trascina
per eliminare
Ora impostiamo anche il bottone di edit Decommentiamo
self.navigationItem.leftBarButtonItem =
self.editButtonItem; in ViewDidLoad:
20. Navigar m竪 dolce..
Nel capitolo precedente abbiamo usato una view modale
Labbiamo presentata col metodo presentModalViewController:
Ora la navigazione 竪 gestita da UINavigationController
Dobbiamo prendere la classe MovieEditorViewController
Copiamo le due classi e il file xib con la solita tecnica
Spostiamo lo xib nel gruppo Resources
21. Alcune Modifiche
Visto che precedentemente occupava tutto lo schermo
Ora la view va modificata con Simulated Interface Elements in IB
Impostare Top Bar a Navigation Bar
Creiamo un IBOutlet in RootViewController
Aggiungiamo MovieEditorViewController *movieEditor; ..
.. la property associata IBOutlet MEVC *movieEditor;
22. Dettagli
Facciamo @synthesize per questa propriet nel file .m
Inseriamo #import "MovieEditorViewController.h" nellheader
Creiamone unistanza in IB
Trasciniamo UViewController dalla Lib in RootViewController
Come identity impostiamo MovieEditorViewController
Connettiamo movieEditor alloggetto view controller
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. Due commenti veloci
Abbiamo istanziato una variabile di tipo Movie
Questa memorizza il contenuto dellArrray
Questo contenuto 竪 poi passato al campo movie del VC
La propriet navigationController 竪 ereditata da RVC
Questa propriet cerca allinterno della gerarchia fino a trovare
un riferimento ad un UINavigationController
25. Il pulsante Done
Per lIBAction done: bisogna cambiare il comportamento
In questo caso sar necessario chiamare il popViewController
Con la propriet animated: settata a YES;
Anche MEVC pu嘆 accedere alla propriet ereditata dal
navigationController
Ora il RVC ottiene il callback a viewWillAppear: e aggiorniamo
la view
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 lindice dellarra y corrispondente a editingMovie
Creiamo un NSIndexPath a quella riga e ricarichiamo la riga
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 sulloggetto target
Loggetto target in questo caso 竪 proprio il RVC
30. Come funziona la navigazione
C竪 un Navigation Controller
La navigazione 竪 organizzata con uno stack
Tipicamente si parte da RootViewController
Si passa ad una serie pi湛 o meno infinita di altri VC
Ognuno riporta un titolo ed un link al precedente
Si passa dal generale al particolare
31. Esaminiamo le cose
Apriamo un nuovo progetto chiamato DVDCase
Andiamo a vedere MainWindow.xib
Esaminiamo il Navigation controller
Troviamo finalmente la Table View
Notiamo che sia dataSource che delegate sono del Files Owner
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
34. Altre modifiche
Andiamo a implementare didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(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. Precisazioni
Abbiamo impostato il titolo del VC in maniera condizionale
La chiamata a pushViewController rende attiva la view del VC
La propriet cabinetController va dichiarata al RVC
Aggiungiamo una variabile istanza e unistruzione @synthesize
Modifichiamo viewDidLoad: per visualizzare il testo nel pulsante
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. Creiamo il nuovo VC
Creiamo una sottoclasse di UITableViewController
Creiamo il nuovo file NIB che contiene linterfaccia utente
Configurare il file NIB per avere una TV e al nostro VC
Aggiungere un outlet in RVC per farle conoscere il nuovo VC
Aggiornare RVC.xib per impostare questo outlet
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. Modifiche
Per connettere loutlet, apriamo RVC.xib e aggiungiamo un VC
Impostare la classe DVDCabinetController nella finestra
Identity
Connettere il Files Owner alloutlet cabinetController
Creiamo una nuova View da Add->New File, View XIB
Sostituiamo la UIView con una UITableView
Impostiamo come classe delloggetto Files Owner DVDCC
40. Connettiamo gli oggetti
Creiamo le connessioni necessarie
Trasciniamo dalloutlet view del FsO al nuovo oggetto
TableView
Scegliere loutlet view
Connettere dataSource e delegate al Files Owner
Per visualizzare i dati 竪 necessario implementare i soliti 2 metodi
42. Ultimi ritocchi
Abbiamo fatto due dizionari per contenere i valori memorizzati
in RVC
Tipicamente non si usa questo tipo di approccio
Risulta per嘆 cos狸 pi湛 leggibile il codice
Modifichiamo i metodi per il ritorno del numero di valori
E personalizziamo la cella affinch辿 mostri il valore corretto
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. 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
46. Cosa fa MapKit
la classe che si occupa della generazione di mappe
particolarmente utile in virt湛 della localizzazione del device
Unendo le due funzionalit si possono ottenere ottimi risultati
La nostra piccola applicazione centrer la mappa sulla nostra
posizione corrente
47. Primo passo
Come prima cosa 竪 necessario aggiungere al progetto i
Framework
Creiamo un nuovo progetto e chiamiamolo FindMe
Utilizziamo il template View-Based Application
Aggiungiamo i Framework MapKit e CoreLocation
Apriamo il file NIB e trascinate un MapView
48. Quasi finito
Abbiamo quasi finito, basta selezionare Show User Location
Selezioniamo il tipo di mappa (Map)
Salviamo e eseguiamo
Il simulatore mostrer una posizione fittizia sullApple Campus
Ora vogliamo che la mappa venga centrata nuovamente e
ingrandita
49. Centrare le mappe
Per centrare le mappe bisogna usare il metodo setRegion:
Il parametro region: 竪 una struttura C simile a CGRect
MKCoordinateRegion ha due parti center e span.center
Il primo 竪 un CLocationCoordinate2D con coordinate del punto
Il secondo 竪 un MKCoordinateSpan e specifica la variazione in
gradi delle coordinate della regione da includere
Centriamo la mappa con .15 di differenza tra le due misure
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 unanimazione
Impostiamo anche un IBOutlet nel codice per MKView
51. Aggiungere annotazioni
Inseriamo MKMapView *_mapView; nel file .h,
Chiamiamo lIBOutlet nella stessa maniera
E poi sintetizziamo dicendo che _mapView = mapView;
Teoricamente dovremo vedere anche il delegato del localizzatore
In realt Show User Location far il lavoro per noi
Per le annotazioni MKAnnotation non definisce le
implementazioni pubbliche
52. Le annotazioni
Per aggiungere unannotazione dobbiamo creare la nostra
specifica implementazione di questo protocollo
Il protocollo definisce una propriet e due metodi opzionali
La propriet 竪 la localizzazione dellannotazione
I metodi sono title e subtitle
Vengono presentati sullannotazione entrambi
Uno il titolo, uno il sottotitolo
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
55. Aggiungere unazione
Teoricamente potremmo decidere di scatenare unazione alla
pressione del tasto
Definiamo lIBAction 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 Files Owner
56. Aggiungiamo la nota alla
mappa
Nel metodo viewDidApper: possiamo inserire lanimazione
Possiamo inserire la nostra istanza di ContactAnnotation
Istanziamo la classe da qualche parte nel codice dove pi湛 ci serve
self.newAnnotation= [ContactAnnotation
annotationWithCoordinate:coordinate];
Chiamiamo il metodo dinserimento con [self.mapView
addAnnotation:sel.newAnnotation];