SlideShare une entreprise Scribd logo
1  sur  57
Télécharger pour lire hors ligne
LE TABLE VIEW
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
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
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:
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
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
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
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
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..
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];
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
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}
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
Proprietà della cella

La cella di default ha tre proprietà principali
  textLabel

  detailTextLabel

  imageView

Per usare detailTextLabel dobbiamo usare uno stile differente
di cella
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)
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
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:
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:
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:
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
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;
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
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];
}
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
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
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
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
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];
}
LA NAVIGAZIONE
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
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
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
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;
}
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
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
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
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
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
Modifiche
Per 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
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
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];
!
}
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
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;
}
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
MAPKIT
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
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
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
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
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
Aggiungere annotazioni
Inseriamo   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
Le annotazioni
Per 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
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
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
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
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];
ALLA PROSSIMA LEZIONE!

Contenu connexe

Similaire à Programming iOS lezione 2

Making iOS UIKit Simulator for MacOS X
Making iOS UIKit Simulator for MacOS XMaking iOS UIKit Simulator for MacOS X
Making iOS UIKit Simulator for MacOS XDaniele Margutti
 
Xcode - Just do it
Xcode - Just do itXcode - Just do it
Xcode - Just do itpragmamark
 
Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftAsp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftStefano Benedetti
 
Migliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsMigliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsAndrea Dottor
 
Wearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchWearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchPaolo Musolino
 
Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Luca Lusso
 
ios 8 - parte 2 - todo-app - ita
ios 8 - parte 2 - todo-app - itaios 8 - parte 2 - todo-app - ita
ios 8 - parte 2 - todo-app - itaDario Rusignuolo
 
ASP.NET MVC 3 - Presentare i dati nella View
ASP.NET MVC 3 - Presentare i dati nella ViewASP.NET MVC 3 - Presentare i dati nella View
ASP.NET MVC 3 - Presentare i dati nella ViewManuel Scapolan
 
How To React - Gestione Stato Applicativo
How To React - Gestione Stato ApplicativoHow To React - Gestione Stato Applicativo
How To React - Gestione Stato ApplicativoAldoNoschese
 
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerQt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerPaolo Sereno
 
Asp.NET MVC Framework
Asp.NET MVC FrameworkAsp.NET MVC Framework
Asp.NET MVC FrameworkDotNetMarche
 
Creazione di una REST API in Liferay
Creazione di una REST API in LiferayCreazione di una REST API in Liferay
Creazione di una REST API in LiferayNunzio Mastrapasqua
 
Zend Framework Workshop Parte2
Zend Framework Workshop Parte2Zend Framework Workshop Parte2
Zend Framework Workshop Parte2massimiliano.wosz
 
ZoeFX: un framework MVC per JavaFX
ZoeFX: un framework MVC per JavaFXZoeFX: un framework MVC per JavaFX
ZoeFX: un framework MVC per JavaFXTiziano Lattisi
 

Similaire à Programming iOS lezione 2 (20)

Making iOS UIKit Simulator for MacOS X
Making iOS UIKit Simulator for MacOS XMaking iOS UIKit Simulator for MacOS X
Making iOS UIKit Simulator for MacOS X
 
Xcode - Just do it
Xcode - Just do itXcode - Just do it
Xcode - Just do it
 
Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftAsp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
 
Migliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsMigliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.js
 
MVC2: non solo tecnologia
MVC2: non solo tecnologiaMVC2: non solo tecnologia
MVC2: non solo tecnologia
 
Wearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchWearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple Watch
 
Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8
 
ios 8 - parte 2 - todo-app - ita
ios 8 - parte 2 - todo-app - itaios 8 - parte 2 - todo-app - ita
ios 8 - parte 2 - todo-app - ita
 
ASP.NET MVC 3 - Presentare i dati nella View
ASP.NET MVC 3 - Presentare i dati nella ViewASP.NET MVC 3 - Presentare i dati nella View
ASP.NET MVC 3 - Presentare i dati nella View
 
How To React - Gestione Stato Applicativo
How To React - Gestione Stato ApplicativoHow To React - Gestione Stato Applicativo
How To React - Gestione Stato Applicativo
 
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerQt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
 
Asp.NET MVC Framework
Asp.NET MVC FrameworkAsp.NET MVC Framework
Asp.NET MVC Framework
 
Vaadin7
Vaadin7Vaadin7
Vaadin7
 
Knockout.js
Knockout.jsKnockout.js
Knockout.js
 
ASP.NET MVC: Full Throttle
ASP.NET MVC: Full ThrottleASP.NET MVC: Full Throttle
ASP.NET MVC: Full Throttle
 
Creazione di una REST API in Liferay
Creazione di una REST API in LiferayCreazione di una REST API in Liferay
Creazione di una REST API in Liferay
 
Zend Framework Workshop Parte2
Zend Framework Workshop Parte2Zend Framework Workshop Parte2
Zend Framework Workshop Parte2
 
Zendframework Parte2
Zendframework    Parte2Zendframework    Parte2
Zendframework Parte2
 
ZoeFX: un framework MVC per JavaFX
ZoeFX: un framework MVC per JavaFXZoeFX: un framework MVC per JavaFX
ZoeFX: un framework MVC per JavaFX
 
Spring Intro
Spring IntroSpring Intro
Spring Intro
 

Programming iOS lezione 2

  • 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 Un’origine dati Un delegato Iniziamo dalla prima Una UITableView è una classe che presenta una tabella a video
  • 4. 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:
  • 5. 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
  • 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 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
  • 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 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. 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: 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. 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 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
  • 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" nell’header Creiamone un’istanza in IB Trasciniamo UViewController dalla Lib in RootViewController Come identity impostiamo MovieEditorViewController Connettiamo movieEditor all’oggetto 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 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
  • 25. 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
  • 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. 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. 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]; }
  • 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 File’s 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
  • 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. 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 un’istruzione @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 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
  • 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 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
  • 40. 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
  • 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. 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 sull’Apple 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 un’animazione Impostiamo anche un IBOutlet nel codice per MKView
  • 51. Aggiungere annotazioni Inseriamo 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
  • 52. Le annotazioni Per 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
  • 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. 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. 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. 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];