i3Factory

La tua Iphone, iPad & Android Application Factory

Visualizza gli articoli con tag tutorial

    Icona Newsstand Icon

    La rivoluzione iOS5

    Molta acqua è passata sotto i ponti da quando abbiamo pubblicato la nostra prima parte di questo tutorial. Ci scusiamo per il ritardo, ma al momento di scrivere eravamo consapevoli delle nuove funzionalità introdotte con iOS5 ma eravamo ancora sotto NDA e non autorizzati a rivelare nulla del SDK. Finalmente siamo ora in grado di fornire l’esempio  della nostra applicazione per riviste e magazine  con compatibilità doppia: iOS4/iOS5 .

    Non passeremo il tempo a spiegare tutte le caratteristiche della funzione Newstand (edicola), tutto sommato stiamo dandovi le informazioni per creare un app per leggere delle riviste e i dettagli d’implementazione Newstand  vanno oltre il nostro scopo originale.
    Abbiamo scritto un tutorial di due parti, presente in inglese nel  blog personale del nostro CTO, che potete leggere qui, e che copre tutti gli aspetti Newstand e le richiesta (da parte di revisori Apple) in caso di abbonamenti.

    In breve, Newstand (edicola) è un nuovo modo di presentare riviste nel iPad e iPhone, dove è sostituita l’icona originale dalla copertina della rivista o giornale, ed è posto sotto uno speciale gruppo dedicato a raccogliere tutte le icone Newstand installate dall’utente.
    Per lo sviluppatore c’è anche un framework, chiamato Newstand Kit, che introduce una nuova metodologia per organizzare, scaricare e installare il contenuto dell’ App.

    L’esempio di applicazione

    La schermata mostra l’aspetto finale dell’ app. Un insieme di nove riviste con ongnuna un differente frutto in copertina.

    È possibile scaricare una rivista, vedere il cambiamento barra di avanzamento mentre l’operazione è in corso e, infine, leggerla. La schermata mostra l’altro aspetto nel Newstand (edicola).
    L’icona tipica è stata sostituita dalla rivista, come la rappresentanza all’interno del gruppo Edicola.
    Invece, se eseguito su un iPad con iOS4 installato apparirà l’icona classica.

    Il codice di un’applicazione completa è disponibile su GitHub. Non considerarla come un codice di produzione, quindi per favore non cercate di riutilizzare così com’è per la vostra app o con i vostri clienti se non avete provato in tutti i possibili casi limite.
    In ogni caso può essere considerato come un valido punto di partenza per le applicazioni reali. In sostanza i principi alla base dell’architettura del codice sono stati descritti nella Parte I di questo tutorial, se non avete ancora letto vi consiglio di saltare al precedente articolo prima di leggere questo, almeno per capire i componenti chiave di tale applicazione.
    Lo scopo di queto tutorial , guida o howto, è quello di capire e tenere la gestione dell’ issues management (controller, da non confondere con “View Controller”) separata il più possibile dalle UI (interfaccie utente). Ciò significa che in teoria il codice che sta dietro Store Manager and Issue Models  può essere riutilizzato anche in un applicazione Mac OSX , in quanto rapporto con cose come la UI è minimo.

    Abbiamo installato questa applicazione utilizzando il modello di base di una singola finestra Xcode (the basic single window Xcode template) e poi aggiunto le due componenti principali del metodo all’avvio dell’applicazione (delegate startup method):

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {    
        // here we create the “Store” instance
        _store = [[Store alloc] init];
        [_store startup];     self.shelf = [[[ShelfViewController alloc] initWithNibName:nil bundle:nil] autorelease];
        _shelf.store=_store;     self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
        self.window.rootViewController = _shelf;
        [self.window makeKeyAndVisible];
        return YES;
    }

    I due componenti sono:

    la classe Store, che rappresenta il blocco Store Manager nell’architettura applicazione, questa classe è una sottoclasse di NSObject e non è legata all’interfaccia utente.
    Il ShelfViewController rappresenta l’UI (interfaccia utente) dell’applicazione. E’ collegata allo Store (negozio) utilizzando una proprietà specifica. Si noti che il controller non avrà accesso alle proprietà Store esposte, ma otterrà le informazioni necessarie attraverso una semplice API.
    Avremmo potuto utilizzare un modello di delega (delegate pattern), invece, ma poichè i due blocchi sono blocchi essenzialmente custom in un’applicazione personalizzata, non c’è proprio bisogno di definire un protocollo per la loro interazione. Possiamo dire che la parte del controller è stato suddiviso in due parti, una per l’interfaccia utente (UI), la mensola (the shelf), e uno per il back-end, il negozio (Store). Il loro legame è tale che la mensola dipende dallo Store (strict link), non viceversa.
    Ogni Store per la comunicazione con il prodotto (shelf) utilizza le notifiche.

    L’applicazione è stata poi integrata con le nuove esigenze Newstand nel plist info. Anche in questo caso dare un’occhiata alla documentazione di Apple per una guida dettagliata.

     

    Modelli e Controller

    Abbiamo un modello in questa applicazione, è il modello Issue che rappresenta un numero singolo del magazine o rivista nello Store (negozio) o nella libreria utente (user library). C’è anche un controller, che è il Store. Come abbiam detto questo controller non è un componente di UI (interfaccia utente), ma l’applicazione di back-end è autosufficiente con questi due componenti. In teoria siamo in grado di recuperare lo statuo negozio e riviste scaricate (store status and download magazines) anche senza alcuna UI (interfaccia utente). Questo è un concetto di base in applicazioni per riviste (Magazine Apps), in cui molti eventi avvengono in background non sono legati all’interazione diretta dell’utente : questo significa che l’applicazione dovrebbe essere in grado di eseguire diverse operazioni, anche se l’interfaccia utente non è stata caricata.

    Il ruolo della “issue class” è quello di rappresentare tutte le proprietà rilevanti rivista, che sia un identificatore univoco, un titolo, una data di uscita, un collegamento alla immagine di copertina, ovviamente il link (URL) al contenuto (che può essere un file PDF, un file epub o un file zip per i pacchetti complessi).
    In particolare, l’identificatore univoco (unique identifier) è un pezzo di dati che deve essere mantenuta lungo la vita dell’ issue: è l’unico modo per identificare univocamente un determinato issue, indipendentemente da problemi di localizzazione (ad esempio, il titolo può cambiare in diversi paesi, ma non l’ID univoco). Inoltre è il link per il modo in Newsstand (edicola) per identificare le issue  (il nome del campo NKIssue) e può anche essere utilizzato per collegare il prodotto con l’App Store, se abbiamo intenzione di implementare gli Acquisti In App o In App Purchases.

    Oltre a  questo ruolo, le issue class avranno un ruolo centrale nel download di una rivista. In sostanza la classe Store (Store class) potra fare uno schedule e quindi potra’ programmare un download, ma questo sarà monitorato  dalla issue class (progress) e poi terminare (installazione effettiva della rivista/magazine ).

    Infine, questa classe ha limitate capacità di rappresentare una rivista già scaricata e disponibile nella libreria utente (user library). Per questo mettiamo a disposizione la semplice isIssueAvailableForRead  che sara utilizzata da parte dell’interfaccia utente per sapere quali interventi sono possibili con un issue (leggere o scaricare) ed eventualmente visualizzarne il contenuto.

    La classe Store è il controller app. E ‘inizializzato all’inizio delle app e la sua istanza non è mai rilasciata. Subito dopo l’inizializzazione DI questa classe verrà recuperato il contenuto dello store (negozio) dal server dell’editore.

    In questo esempio abbiamo deciso di attuare il contenuto negozio come un semplice elenco delle proprietà, e poi istruire il negozio per recuperare questa lista di proprietà, decodificarlo e creare gli oggetti di emissione e, infine, scaricare le loro immagini di copertina. Tutto questo è fatto in modo asincrono utilizzando la Grand Central Dispatch e alla fine una notifica verrà inviata per informare tutti gli oggetti interessati (in particolare il controller della vista) che i contenuti Store sono pronti e l’interfaccia utente può essere tranquillamente visualizzata.
    Si noti che il negozio è stato rappresentato da un property status. Abbiamo ignorato il  setter method, di inviare una notifica che informa ogni osservatore interessato del nuovo stato. Per semplicità abbiamo deciso di limitare i possibili stati di “non inizializzato”, “download”, “pronto” e “errore”. Una applicazione più compless può introdurre gli stati extra se necessario. Infine come ripiego in caso di collegamento mancante (l’utente deve essere in grado di accedere al suo / suoi contenuti, anche se non collegato a Internet) si potrà ricaricare una copia salvata in locale del negozio.

    Il pezzo centrale del codice è nel metodo downloadStoreIssues della classe, che riportiamo di seguito:

    -(void)downloadStoreIssues {
    self.status=StoreStatusDownloading;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
    NSArray *_list = [[NSArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://www.viggiosoft.com/media/data/iosblog/magazine/store.plist"]];
    if(!_list) {
    // let’s try to retrieve it locally
    _list = [[NSArray alloc] initWithContentsOfURL:[self fileURLOfCachedStoreFile]];
    }
    if(_list) {
    // now creating all issues and storing in the storeIssues array
    [_list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    NSDictionary *issueDictionary = (NSDictionary *)obj;
    Issue *anIssue = [[Issue alloc] init];
    anIssue.issueID=[issueDictionary objectForKey:@"ID"];
    anIssue.title=[issueDictionary objectForKey:@"Title"];
    anIssue.releaseDate=[issueDictionary objectForKey:@"Release date"];
    anIssue.coverURL=[issueDictionary objectForKey:@"Cover URL"];
    anIssue.downloadURL=[issueDictionary objectForKey:@"Download URL"];
    anIssue.free=[(NSNumber *)[issueDictionary objectForKey:@"Free"] boolValue];
    [anIssue addInNewsstand];
    [storeIssues addObject:anIssue];
    [anIssue release];
    // dispatch cover loading
    if(![anIssue coverImage]) {
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:anIssue.coverURL]];
    if(imgData) {
    [imgData writeToURL:[anIssue.contentURL URLByAppendingPathComponent:@"cover.png"] atomically:YES];
    }
    });
    }
    }];
    // let’s save the file locally
    [_list writeToURL:[self fileURLOfCachedStoreFile] atomically:YES];
    [_list release];
    self.status=StoreStatusReady;
    } else {
    ELog(@”Store download failed.”);
    storeIssues = nil;
    self.status=StoreStatusError;
    }
    });
    }

     

    Si noti che nel codice qui sopra, per semplicità, abbiamo messo in coda il  download della copertina (cover) subito dopo il property list download (download elenco di proprietà).
    Probabilmente questo non è il modo migliore per fare questo, stiamo aggiungendo ulteriori networking steps  prima di presentare lo status dell’applicazione, con possibili ritardi se le condizioni della rete non sono buone. Possiamo fare questo in un esempio in cui sappiamo che il numero di problemi è limitato, probabilmente in una applicazione vera e propria ha più senso farlo in un processo in background e quindi notificare all’interfaccia utente di aggiornare il suo status ogni volta che una nuova copertina è pronta da visualizzare.

     

    La “View Controller”

    L’interfaccia utente si sveglia immediatamente, e cambierà il suo aspetto, basato sulle comunicazioni provenienti dal negozio. Quando il centro di notifica consegnerà al negozio “Sono pronto” come  messaggio per l’interfaccia utente, questo verrà caricato tutte le rappresentazioni problema UI (la classe CoverViewè  nel codice, una view di base con la logica dell’applicazione davvero minimo) e mostrare la shelf (mensola) all’ utente.

    A questo punto l’applicazione ha terminato la sua elaborazione back-end ed è in attesa di comandi dell’utente. Qui abbiamo due possibilità:

    Una rivista è stata scaricata, l’utente vedrà un pulsante “Leggi”, cliccando su di essa egli sarà in grado di leggerla.
    Nel nostro esempio tutti i nostri contenuti sono costituiti di file Pdf, abbiamo deciso di utilizzare il framework Quick Look in iOS, che è sufficiente per i nostri scopi.
    Una rivista non è ancora stata scaricata, l’utente vedrà un pulsante “Download”, cliccandoci sopra si avvia il download e ti mostrano una barra di avanzamento (progress bar). Alla fine avremo bisogno di sostituire l’etichetta del pulsante e nascondere il progress. Vedremo questa parte in modo più dettagliato.

    La view controller dipende dallo Store (negozio). Al fine di ottenere le informazioni sull’issue(numero dell’issue, il dettaglio di ogni numero/issue) questa non avrà accesso direttamente alle proprietà del negozio, ma userà una API molto semplice, fatta di tre metodi:

    /* “numberOfIssues” is used to retrieve the number of issues in the store */
    -(NSInteger)numberOfStoreIssues;/* “issueAtIndex:” retrieves the issue at the given index */
    -(Issue *)issueAtIndex:(NSInteger)index;/* “issueWithID:” retrieves the issue with the given ID */
    -(Issue *)issueWithID:(NSString *)issueID;

    Basandoci su questa informazione, e sulle propieta’ dell’ Issue (properties), si creerà la Issue view representation (CoverView) e sarà visualizzata sullo schermo.

    Il download di una rivista o giornale

    In una Magazine App ci sono tre sezioni critiche:
    recuperare e visualizzare i contenuti negozio, scaricare il contenuto e, infine, leggerlo (un buon lettore PDF o EPUB  è obbligatorio in un app del genere, non è lo scopo di questo tutorial, mirato a spiegare l’architettura e le tecniche necessarie per rendere tale applicazione, ma è una parte rilevante l’esperienza utente).

    Il nostro approccio nel download della rivista è che l’utente deve essere completamente libero di fare qualsiasi azione e tale azione non deve interferire con il risultato del download.
    Ora molte applicazioni sono solite prendere una scorciatoia: hanno messo uno spinner al centro dello schermo, poi bloccano qualsiasi interazione dell’utente con gli oggetti dell’interfaccia utente dietro lo spinner per poi chiedere all’utente di aspettare.
    E ‘facile fare questo, ma non è la migliore esperienza utente.
    Durante attesa l’utente deve poter leggere un altro numero (issue), poter navigare all’interno del negozio o decidere di passare temporaneamente a un’altra applicazione o infine può perdere temporaneamente il collegamento con la rete.
    Newsstand Kit fornisce una metodologia a livello di sistema che semplifica (in alcuni casi) la vita degli sviluppatori, ma al tempo stesso elimina ogni scusa per non fare un buon lavoro in termini di user experience.

    Non appena l’utente attiva un nuovo download, il view controller invierà la sua richiesta di download alla classe Store. Nel codice qui sotto potete vedere il scheduleDownloadOfIssue:code.
    Questo metodo prepara la richiesta di rete e la invierà in background. Si noti come abbiamo diviso il comportamento applicazione in base alla versione del sistema operativo siamo in. Se è iOS5 allora dobbiamo utilizzare l’approccio Newsstand-Edicola – dove il download saranno gestiti dal sistema in una coda Edicola -, se siamo in iOS4 faremo seguire una metodologia classica basata su NSOperation: in questo caso mi sono perso per la semplicità per ottenere la  content length del contenuto da scaricare, nel caso iOS4 la barra di avanzamento non viene visualizza. Questa informazione è invece fornita “for free” da Newsstand.

    -(void)scheduleDownloadOfIssue:(Issue *)issueToDownload {
    NSString *downloadURL = [issueToDownload downloadURL];
    NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadURL]];
    if(isOS5()) {
    // iOS5 : use Newsstand
    NKIssue *nkIssue = [issueToDownload newsstandIssue];
    NKAssetDownload *assetDownload = [nkIssue addAssetWithRequest:downloadRequest];
    [assetDownload downloadWithDelegate:issueToDownload];
    } else {
    // iOS4 : use NSOperation
    NSURLConnection *conn = [NSURLConnection connectionWithRequest:downloadRequest delegate:issueToDownload];
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startDownload:) object:conn];
    if(!downloadQueue) {
    downloadQueue = [[NSOperationQueue alloc] init];
    downloadQueue.maxConcurrentOperationCount=1;
    }
    [downloadQueue addOperation:op];
    [downloadQueue setSuspended:NO];
    }
    }// iOS4 only
    -(void)startDownload:(id)obj {
    NSURLConnection *conn = (NSURLConnection *)obj;
    [conn start];
    }

    Nei due casi mi piacerebbe sottolineare il fatto che lo “Store” avvia l’operazione di download, ma poi  delega ogni ulteriore elaborazione alla parte interessata, l’ Issue da scaricare. Così sarà la classe Issue che monitorerà il download e poi lo finalizzerà.

    La issue class (classe di Emissione) si comporterà come delegato dell’operazione di scaricamento innescata dalla Store class. Il delegate protocolrisulta differente se si sta utilizzando “Edicola” oppure no. Nel primo caso sarà necessario per essere compatibile con il protocollo NSURLConnectionDownloadDelegate mentre nel secondo caso il protocollo da rispettare sara’ il  non documentato (o: documentato solo nel file header ) NSURLConnectionDataDelegate che è una “spin-off” di il NSURLConnectionDelegate classico.
    La differenza tra i due protocolli è che il primo scriverà nel file system, l’altro in memoria.
    Anche in questo caso non usare il “data” approach a fini di produzione, qui si sta caricando tutto il contenuto in memoria e quindi salvando su disco quando il contenuto è stato completamente scaricato: in realtà non è l’approccio migliore se il contenuto è centinaia di megabyte, la vostra applicazione sarà certamente crash.

    Al fine di monitorare visivamente l’avanzamento e quindi aggiornare l’interfaccia utente, abbiamo deciso, essendo coerente dei nostri principi, per tenere l’ application store controller  indipendente per ogni scelta dell’interfaccia utente. Per fare questo ci avvaliamo di KVO e notification. In sostanza quando il view controllerinizia un download, sarà impostato e la “magazine view” come “notification observers” del risultato download, al fine di aggiornare il suo status non appena termina il download (con successo o con errore):

    -(void)downloadIssue:(Issue *)issue updateCover:(CoverView *)cover {
    cover.progress.alpha=1.0;
    cover.button.alpha=0.0;
    [issue addObserver:cover forKeyPath:@"downloadProgress" options:NSKeyValueObservingOptionNew context:NULL];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
    [_store scheduleDownloadOfIssue:issue];
    }
    Sia con la “cover view” che il “view controller”, sarà necessario annullare la registrazione dal centro della notifica non appena termina l’operazione di download. Oltre a permettere la visione di copertura per tenere traccia del progress status, come il download comincia, sarà registrato come “KVO observer” della proprietà DownloadProgress del “issue”. Questo significa che per ogni cambiamento di questa proprietà, che si verifica durante la fase di scaricamento, la cover view sara’ informata del cambiamento per aggiornare la barra di avanzamento (quindi abbiamo qui una separazione di  back-end property, del download progress, dell’ UI, e la UIProgressBar). La cover vieweliminarà la registrazione non appena termina il download.Quando termina il download, l’ Issue instance  (istanza di emissione) copierà il contenuto scaricato fino alla destinazione finale. Nell’ambito Newstandquesta destinazione è specificato dal sistema, in iOS4 lo copia nella directory di cache per essere compatibile con i requisiti icloud (sì, iOS4 non funziona con icloud ma la nostra applicazione è la stessa per entrambe le generazioni del sistema operativo, quindi dobbiamo essere buoni cittadini, in ogni caso).Nel caso Newstand avremo anche bisogno di aggiornare l’immagine di copertina per l’icona Edicola. Lo faremo con un semplice comando all’interno del codice che gestisce la cessazione download (alla fine dobbiamo anche inviare la notifica di fine download di cui abbiamo parlato in precedenza):
    -(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
    // copy the file to the destination directory
    NSURL *finalURL = [[self contentURL] URLByAppendingPathComponent:@”magazine.pdf”];
    ELog(@”Copying item from %@ to %@”,destinationURL,finalURL);
    [[NSFileManager defaultManager] copyItemAtURL:destinationURL toURL:finalURL error:NULL];
    [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:NULL];
    // update Newsstand icon
    [[UIApplication sharedApplication] setNewsstandIconImage:[self coverImage]];
    // post notification
    [self sendEndOfDownloadNotification];
    }

    Conclusioni

    Questa è la conclusione di questo tutorial. Abbiamo deciso dopo un lungo intervallo di fare uno sforzo per proporre una applicazione completa valida sia per ambienti iOS4 e iOS5 . Nel codice si trovano cose più interessanti, ad esempio un “aggancio” allo Store Kit: questo è un problema tipico non considerato dagli sviluppatori quando fanno le applicazioni che vendono magazines.
    In tal caso la memorizzazione del prezzo del’issue nel server dell’editore non è di aiuto poicheì dobbiamo recuperare le informazioni sui prezzi alla fonte, che è l’App Store. Per fare questo la nostra applicazione deve – in modo asincrono – fsre query su iTunes Store per ottenere i prezzi di tutte le pubblicazioni e quindi visualizzarle una volta recuperate.

    Non abbiamo aggiunto questo ulteriore passaggio nel codice, solo il “gancio” per future estensioni, ma ovviamente, se richiesto dai nostri lettori la avremo possibilità di estendere ulteriormente questo tutorial.

    Have a nice Code with

    Carlo Vigiani

      Leggendo un’interessantissimo articolo di Marc Edwards su Smashing Magazine ho deciso di citarne e tradurne le parti piu’ significative dato che spesso mi trovo a dover parlare con i clienti della effettiva necessità di progettare le proprie app tenendo conto che le tecnologie audiovisive sono in costante evoluzione.
      L’iPhone 4 dispone di una risoluzione di gran lunga superiore (614.400 pixel) rispetto ai modelli iPhone precedenti e ha di fatto un display quadruplicato di 153.600-pixel  anche se lo schermo ha le stesse dimensioni fisiche, così quei punti in più sono utili per ulteriori dettagli – due volte il dettaglio in orizzontale, e due volte in verticale.

      Lo Scaling dell’interfaccia utente (UI) per i display a  maggiore dettaglio – o piu’ spesso un aumento della dimensione display – non è un problema nuovo. Le interfacce che sono in grado di scalare sono dette: ” indipendenti dalla risoluzione” (resolution independence).

      In un recente articolo, Neven Mrgan ha descritto l’ indipendenza dalla risoluzione: “RI [risoluzione indipendente] come obiettivo, e non come una tecnica. Significa avere contenuti e risorse che potranno essere significative in dimensioni diverse. “Se è un obiettivo, non una tecnica specifica, quindi quali tecniche esistono? Come Apple ha risolto il problema di Ios?

      Layout Fluidi (Fluid Layout)

      Mentre le applicazioni che sfruttano elementi  nativi dell’interfaccia utente di Apple richiedono molto meno lavoro quando le si progetta per la visualizzazione Retina, ciò che ci interessa altamente personalizzati, applicazioni grafiche-driven che necessitano di una buona dose di lavoro per sfruttare al massimo le Retina display.

      Sebbene non sia strettamente indipendente dalla risoluzione, l’utilizzo di un layout liquido può aiutare a gestire un app per approfittare di uno schermo più grande  operando sul padding o modificando il layout dinamico. Moltissime applicazioni Mac, Windows e  per Linux utilizzano questo metodo, cosi’ come fanno alcuni siti web.

      Questo è parzialmente cio’ che Apple ha gestito con la differenza di risoluzione da iPhone a iPad – molti elementi dell’interfaccia utente hanno la stessa dimensione in pixel, ma “padded” in modo da utilizzare la parte reale dello schermo. La barra di stato è un buon esempio di questo metodo. Funziona perché la densità dei pixel del 3GS iPhone e iPad sono simili (163ppi vs 132  ppi).

      Layout fluido e’ utile o quando il cambiamento di densità di pixel è minore, ma non sono di aiuto quando si passa da un display iOS non-Retina ad uno Retina (163 ppi a 326 ppi). L’immagine seguente mostra cosa sarebbe successo se una applicazione per iPhone è stata semplicemente ridimensionata per soddisfare i display ad alta risoluzione di iPhone 4. Pulsanti e zone di touch sarebbero della stessa dimensione in pixel, ma la metà in termini di dimensioni fisiche a causa della maggiore densità di pixel, rendendo le cose più difficili da leggere e da toccare.

      Just-in-time Resolution Independence

      Un altro approccio per la gestione di differenti risoluzioni e densità dei pixel è di disegnare tutto utilizzando il codice o le immagini vettoriali (come i PDF), in fase di runtime. L’utilizzo del vettoriale Ti permette di designare o scrivere codice una sola volta, e per display a qualsiasi risoluzione, anche a scala frazionata.

      Purtroppo, utilizzando immagini vettoriali si tende ad essere più avidi di risorse e mancanza di controllo livello di pixel. L’aumento delle risorse non può essere un problema per un desktop, ma è un problema rilevante per un sistema operativo mobile. La mancanza di controllo del livello di pixel è un vero e proprio problema per gli elementi più piccoli . Modificando delle dimensioni di un’icona di un solo pixel  si perde chiarezza.

      Neven Mrgan sottolinea in suo famoso articolo che abbiamo gia citato  che:

      “… Semplicemente non è possibile creare ottimi, icone dettagliate che possono essere arbitrariamente ridotte a dimensioni molto piccole, mantenendo la chiarezza. Piccole icone sono delle caricature: esagerano alcune caratteristiche, basta allineare le forme su una griglia. Anche se tutte le icone possono essere eseguite come vettori, la dimensione più grande non sarebbe mai scalata in basso bene “.

      Anche se qui si sta parlando esclusivamente di icone, descrizione di Neven Mrgan è adatta per la maggior parte degli elementi dell’interfaccia utente. Le decisioni di immagini in scala sono un lavoro da creativo, non da meccanico. Gli elementi vettoriali non sono adatti per tutte le risoluzioni, se si da valore alla qualità del risultato.

      Ahead-of-time Resolution Independence

      I migliori risultati di qualità – e il metodo che Apple ha scelto per la transizione dal iPhone 3G a iPhone 4  – proviene da immagini pre-renderizzate, costruite per i dispositivi particolari, su risoluzioni specifiche: sviluppate  progetti su misura per ogni formato richiesto, se volete. E ‘più lavoro, ma le immagini in pre-rendering assicurno sempre il miglior risultato possibile.

      Apple ha scelto di raddoppiare esattamente la risoluzione del iPhone 3GS  per l’iPhone 4, rendendo il fattore scala ancora più semplice (diverso dall’ approccio di Google e Microsoft – si noti che questo articolo non è rilevante per l’ultima versione di Microsoft sistema operativo mobile – dimostrando ancora una volta che controllare l’intero stack ha dei vantaggi enormi).


      Attualmente, ci sono tre risoluzioni IOS:

      * 320 × 480 (iPhone / iPod touch)
      * 640 × 960 (4 iPhone e iPod con display a Retina)
      * 768 × 1024 / 1024 × 768 (iPad)

      In pochi anni, sembra altamente probabile che la line-up saranno:

      * 640 × 960 (iPhone / iPod touch con display retina)
      * 1536 × 2048 / 2048 × 1536 (iPad con display retina)
      * Qualche tipo di periferica IOS desktop iMac dimensioni con un display Retina

      Ci sono differenze significative tra la progettazione di applicazioni per iPhone  e per iPad, il layout delle app deve essere in parte o completamente rielaborato  in ogni caso – non si può semplicemente scalare per  iPad la vostra app per iPhone , e aspettarsi che tutto funzioni bene o sche abbia un usabiliyà su iPad. La differenza di dimensione dello schermo e il fattore di forma significano che ogni dispositivo dovrebbe essere trattato separatamente. La dimensione del dell’iPad permette di visualizzare più informazioni sullo schermo, mentre le applicazioni per iPhone in genere hanno bisogno di essere più profonde, con diversi livelli per poter fruire bene di tutte le informazioni.

        Questa secondo articolo dedicato alla progettazione del layout per il retina display proviene sempre dalla lettura e traduzione dell’interessante articolo articolo di Marc Edwards su su Smashing Magazine

        Costruire progetti scalabili

        Costruire applicazioni per l’iPhone 4 display Retina prevede la creazione di due serie di immagini, un a 163 ppi e un altr a 326 ppi. Le immagini A 326  ppi dovra’ includere @ 2x alla fine del nome del file, per indicare che essi, sono al doppio della risoluzione.

        Quando si tratta di costruire elementi di un interfaccia utente in grado di scalare facilmente con Adobe Photoshop, le bitmap sono il tuo nemico, perché “pixelizzano” o si sfocano quando se ne modifica la scala. La soluzione è quella di creare un colore a tinta unita, modelli o layers con maschere vettoriali (solo assicurarsi di avere “snap to pixel” attivo quando possibile).  A volte, il passaggio a tutti i vettori non ha vantaggi significativi.

        Prima che qualcuno ne parli non si stanno suggerendo dei metodi nuovi, e sicuamente molti progettisti di icone è lavorano in questo modo da anni.

        Di norma e’ meglio disegnare elementi semplici direttamente in Photoshop utilizzando il Tool col Rettangolo arrotondato. Disegnare cerchi utilizzando il Rounded Rectangle Tool con un raggio d’angolo molto ampio, perché lo strumento ellisse non può fare lo snap  di pixel.
        I gruppi di layer possono avere maschere vettoriali , e si utlizzano per il compositing complesso (opzione-trascinare una maschera da un altro livello per creare una maschera di gruppo).

        oggetti più complessi vengono trascinati in Adobe Illustrator per l’esatta dimensione dei pixel, e poi incollate in Photoshop come un shape layer. Bisogna fare attenzione quando si incolla in Photoshop, il risultati non si allineano sempre come dovrebbero – è spesso un mezzo  pixel fuori l’asse x, asse y o entrambi. La soluzione è lo zoom, bisogna scorrere il documento con lo strumento Mano e incollare di nuovo. Ripetere l’operazione fino a quando si allinea tutto. E’ esasperante, e il metodo funziona dopo alcuni tentativi. Un’altra opzione è quella di ingrandire fino al 200%, selezionare il percorso con la selezione diretta di utensili, e spostarla di una volta, fino a che si muoverà tutto esattamente 0.5px.

        Anche gli oggetti più complessi, che richiedono più colori vengono disegnati in Illustrator per l’esatta dimensione dei pixel, e quindi incollati in Photoshop come oggetto avanzato. E ‘l’ultima risorsa, anche se – gradienti non sono dithered, e la modifica successiva risulterà più difficile.

        Se avete bisogno di usare un bitmap per una texture, ci sono tre opzioni: usare un pattern layer, un pattern layer style, o costruire un layer bitmap con le dimensioni 2 × e poi trasformarlo in un oggetto avanzato. E’ preferibile usare pattern layer styles, nella maggior parte dei casi, ma con attenzione: i patterns vengono scalati con l’interpolazione bicubica quando si scala l’intero documento, in modo che diventino “softer “.  La soluzione è creare due versioni di ogni pattern (modello), quindi modificare manualmente il “pattern layer styles “per il modello corretto dopo la scalatura – un poco noioso, ma del tutto pratico.


        Scalare l’immagine (Scaling Up)

        A questo punto, il progetto dovrebbe essere in grado di scalare al doppio esattamente e senza intoppi.

        Normalmente si prepara prima  una Action di Photoshop che permette di fare uno snapshot della cronologia, poi la scala al 200%. Ciò significa, che si puo’ì avere la risoluzione al display retina con solo un clic. Se Vi senti sicuri e  avete costruito tutto bene, dovreste essere in grado di scalare, modificare, poi ri-scala verso il basso e continuare a modificare senza alcun tipo di degradazione. Se avete problemi, uno snapshot è lì pronta. Utilizzando un unico documento per entrambe le risoluzioni, significa non dover tenere due documenti in sincronia – un enorme vantaggio.

        Una avvertimento: i “layer styles” possono contenere solo valori interi. Se si modifica un ombra offset da 1 px con il documento a 2 × dimensioni, e poi scala verso il basso, il valore finirà come 1 px, perché non può essere pari allo 0,5 px (un valore non intero). Se si richiede modifiche specifiche per la versione 2 × del file di Photoshop, dovrete salvare quella versione in un file separato.

        Esportazione, exporting.

        Ora,  qualche brutta notizia: il processo di esportazione di tutte le immagini per costruire un’applicazione può essere estremamente noioso, e non ci sono molti consigli in questa fase che possano aiutarvi.

        Il miglior metodo di esportazione sembra essere: attivare il layer che si desidera visibile, fare un perimetro di selezione dell’elemento, quindi utilizzare Copia elementi uniti e incollare la selezione in un nuovo documento – non è molto divertente quando si hanno centinaia di immagini da esportare.

        Il problema è amplificato quando si salva per l’esposizione Retina, dove ci sonoil doppio delle immagini ; ad ogni immagine a 1 × deve corrispondere un  immagini 2 ×  con massima precisione.

        La soluzione migliore sembra essere la seguente:

        * Crea il tuo design a 1 ×
        * Utilizzare Copia elementi uniti per salvare tutte le 1 × immagini
        * Duplicare l’intera cartella contenente le immagini a 1 ×
        * Utilizzare Automator per aggiungere @ 2x a tutti i nomi dei file
        * Aprire ogni @ 2x immagine ed eseguire la “Scala del 200%” azione di Photoshop. Questo ti dà un file con il corretto nome del file e dimensione, ma con contenuti upscaled
        * Scala il tuo  documento di progettazione principale Photoshop del 200%
        * Utilizzare Copia elementi uniti (Copy Merged) per incollare gli elementi di qualità superiore in ogni @ 2x documento, disattivare il livello di qualità inferiore, quindi salvare per il Web, sovrascrivendo il file.

        In alcuni casi, l’opzione di Photoshop “Esporta i livelli per i file” (Export Layers To Files) può aiutare. Lo script può essere trovato nel menu File.