Programming iOS lezione 2

57
LE TABLE VIEW

description

 

Transcript of Programming iOS lezione 2

Page 1: Programming iOS lezione 2

LE TABLE VIEW

Page 2: Programming iOS lezione 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

Page 3: Programming iOS lezione 2

Dettagli

Una tabella è costituita da tre elementi:

Una view

Un’origine dati

Un delegato

Iniziamo dalla prima

Una UITableView è una classe che presenta una tabella a video

Page 4: Programming iOS lezione 2

Origine dati per una table view

Un’origine 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 l’inserimento, l’eliminazione e l’ordinamento di righe nella tabella

I metodi richiesti sono tableView:numberOfRowsInSection: e TableView:cellForRowAtIndexPath:

Page 5: Programming iOS lezione 2

Delegato

Consente all’applicazione host di avere maggior controllo sull’aspetto e il comportamento della casella

Riceve notifiche per le varie azioni dell’utente

Altri metodi consentono al delegato di fornire view personalizzate

Page 6: Programming iOS lezione 2

Navighiamo nella tabellaCreiamo 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

Page 7: Programming iOS lezione 2

Dove si trova la tabella?

Aprite RootViewController.xib, e vedrete il contenuto come singolo oggetto UITableView

Vediamo come dataSource e delegate sono connessi al F’sO

Per tornare alla precedente astrazione vediamo come:

RootViewController fa da delegato e origine dati

La classe fornisce i metodi minimi per eseguire l’applicazione

Page 8: Programming iOS lezione 2

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

Page 9: Programming iOS lezione 2

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..

Page 10: Programming iOS lezione 2

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];

Page 11: Programming iOS lezione 2

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

Page 12: Programming iOS lezione 2

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}

Page 13: Programming iOS lezione 2

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

Page 14: Programming iOS lezione 2

Proprietà della cella

La cella di default ha tre proprietà principali

textLabel

detailTextLabel

imageView

Per usare detailTextLabel dobbiamo usare uno stile differente di cella

Page 15: Programming iOS lezione 2

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)

Page 16: Programming iOS lezione 2

Riutilizzo delle celle

Nel 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

Page 17: Programming iOS lezione 2

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:

Page 18: Programming iOS lezione 2

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:

Page 19: Programming iOS lezione 2

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:

Page 20: Programming iOS lezione 2

Navigar m’è dolce..

Nel capitolo precedente abbiamo usato una view modale

L’abbiamo 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

Page 21: Programming iOS lezione 2

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;

Page 22: Programming iOS lezione 2

Dettagli

Facciamo @synthesize per questa proprietà nel file .m

Inseriamo #import "MovieEditorViewController.h" nell’header

Creiamone un’istanza in IB

Trasciniamo UViewController dalla Lib in RootViewController

Come identity impostiamo MovieEditorViewController

Connettiamo movieEditor all’oggetto view controller

Page 23: Programming iOS lezione 2

Modifica di un elementotableView: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];}

Page 24: Programming iOS lezione 2

Due commenti veloci

Abbiamo istanziato una variabile di tipo Movie

Questa memorizza il contenuto dell’Arrray

Questo contenuto è poi passato al campo movie del VC

La proprietà navigationController è ereditata da RVC

Questa proprietà cerca all’interno della gerarchia fino a trovare un riferimento ad un UINavigationController

Page 25: Programming iOS lezione 2

Il pulsante Done

Per l’IBAction 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

Page 26: Programming iOS lezione 2

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

Page 27: Programming iOS lezione 2

Aggiungiamo un elementoPrima 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

Page 28: Programming iOS lezione 2

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];}

Page 29: Programming iOS lezione 2

LA NAVIGAZIONE

Page 30: Programming iOS lezione 2

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

Page 31: Programming iOS lezione 2

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 File’s Owner

Page 32: Programming iOS lezione 2

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

Page 33: Programming iOS lezione 2

Comportamento del VCInvece 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;}

Page 34: Programming iOS lezione 2

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

Page 35: Programming iOS lezione 2

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 un’istruzione @synthesize

Modifichiamo viewDidLoad: per visualizzare il testo nel pulsante

Page 36: Programming iOS lezione 2

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

Page 37: Programming iOS lezione 2

Creiamo il nuovo VC

Creiamo una sottoclasse di UITableViewController

Creiamo il nuovo file NIB che contiene l’interfaccia 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

Page 38: Programming iOS lezione 2

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

Page 39: Programming iOS lezione 2

ModifichePer connettere l’outlet, apriamo RVC.xib e aggiungiamo un VC

Impostare la classe DVDCabinetController nella finestra Identity

Connettere il File’s Owner all’outlet cabinetController

Creiamo una nuova View da Add->New File, View XIB

Sostituiamo la UIView con una UITableView

Impostiamo come classe dell’oggetto File’s Owner DVDCC

Page 40: Programming iOS lezione 2

Connettiamo gli oggetti

Creiamo le connessioni necessarie

Trasciniamo dall’outlet view del F’sO al nuovo oggetto TableView

Scegliere l’outlet view

Connettere dataSource e delegate al File’s Owner

Per visualizzare i dati è necessario implementare i soliti 2 metodi

Page 41: Programming iOS lezione 2

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];!}

Page 42: Programming iOS lezione 2

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

Page 43: Programming iOS lezione 2

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;}

Page 44: Programming iOS lezione 2

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

Page 45: Programming iOS lezione 2

MAPKIT

Page 46: Programming iOS lezione 2

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

Page 47: Programming iOS lezione 2

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

Page 48: Programming iOS lezione 2

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 sull’Apple Campus

Ora vogliamo che la mappa venga centrata nuovamente e ingrandita

Page 49: Programming iOS lezione 2

Centrare le mappePer 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

Page 50: Programming iOS lezione 2

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

Page 51: Programming iOS lezione 2

Aggiungere annotazioniInseriamo MKMapView *_mapView; nel file .h,

Chiamiamo l’IBOutlet 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

Page 52: Programming iOS lezione 2

Le annotazioniPer aggiungere un’annotazione dobbiamo creare la nostra specifica implementazione di questo protocollo

Il protocollo definisce una proprietà e due metodi opzionali

La proprietà è la localizzazione dell’annotazione

I metodi sono title e subtitle

Vengono presentati sull’annotazione entrambi

Uno il titolo, uno il sottotitolo

Page 53: Programming iOS lezione 2

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

Page 54: Programming iOS lezione 2

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

Page 55: Programming iOS lezione 2

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

Page 56: Programming iOS lezione 2

Aggiungiamo la nota alla mappa

Nel metodo viewDidApper: possiamo inserire l’animazione

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 d’inserimento con [self.mapView addAnnotation:sel.newAnnotation];

Page 57: Programming iOS lezione 2

ALLA PROSSIMA LEZIONE!