Costruire un lettore per iPad per la guerra dei mondi

Questo tutorial utilizzerà il progetto open source di Leaves per creare un semplice lettore per iPad La guerra dei mondi di H.G. Wells. Lungo la strada, daremo un'occhiata al codice che alimenta il progetto Leaves, discuteremo i dettagli di implementazione ed esploreremo alcune opzioni alternative per ottenere un effetto simile.

Informazioni sul progetto Foglie

Leaves è un componente iOS open-source che simula una transizione di pagina tra le visualizzazioni del contenuto, in modo molto simile alla transizione trovata nell'applicazione iBooks ufficiale di Apple. Il progetto è stato originariamente scritto da Tom Brow e reso disponibile su GitHub, dove è stato successivamente biforcato da Ole Begemann per aggiungere il supporto per i layout multi-pagina.

Per vedere il progetto Leaves in azione, dai un'occhiata alla seguente demo video del progetto che questo tutorial ti insegnerà a creare:

Ovviamente, l'effetto di curling della pagina mostrato sopra non è univoco né per questa demo né per l'applicazione iBooks. Anche altre applicazioni iOS native (come l'app Maps) usano un effetto simile. Per il backstory completo su come Apple riesce a realizzare questo nelle loro applicazioni e perché gli sviluppatori di SDK iOS devono ricorrere a un componente come Leaves, guarda "App Store-Safe Page Curl Animations" di Ole Begemann e "Apple's iBook Dynamic Page Curl" di Steven Troughton-Smith.

Torneremo su alcune delle teorie dietro il progetto Leaves, ma andiamo avanti e saltiamo nel creare il nostro Guerra dei mondi lettore per avere un'idea di come il codice appare in azione.

Costruire il lettore PDF WOTW

Passaggio 1: scarica le risorse del progetto

Il file di download allegato a questo post di Mobiletuts contiene il codice sorgente di Leaves e varie risorse di dominio pubblico (incluso il file Guerra dei mondi testo) utilizzato nel progetto.

Passaggio 2: crea un nuovo progetto Xcode

Apri Xcode e crea un nuovo progetto usando il modello "View-based Application". Assegna un nome al progetto "WOTW" e seleziona "iPad" dal menu a discesa della famiglia di dispositivi.

Passaggio 3: aggiungere le risorse del progetto a Xcode

Trascina e rilascia i seguenti file nel gruppo "File di supporto" in Xcode:

Tutti i file sopra riportati possono essere trovati nella cartella "Risorse" del download allegato a questo tutorial.

Successivamente, aggiungi il codice componente Leaves effettivo. Crea un nuovo gruppo chiamato "Foglie" nella cartella "WOTW" nel navigatore del progetto Xcode, quindi trascina e rilascia i seguenti file nel gruppo Foglie:

  • Utilities.h
  • Utilities.m
  • LeavesCache.h
  • LeavesCache.m
  • LeavesView.h
  • LeavesView.m
  • LeavesViewController.h
  • LeavesViewController.m

NOTA: assicurati di selezionare la casella di controllo "Copia elementi nella cartella del gruppo di destinazione" quando aggiungi i file sopra.

Passaggio 4: collegamento di QuartzCore Framework

L'animazione creata da Leaves dipende dal framework QuartzCore. Di conseguenza, dovrai collegare questo framework al tuo progetto per far funzionare Leaves. Per fare ciò in Xcode 4, iniziare selezionando "WOTW" nel Navigatore progetto. Quindi, selezionare il target "WOTW" e quindi la scheda "Fasi di creazione". Quindi espandi il menu "Collega binarie con librerie" e fai clic sul simbolo più per aggiungere un nuovo framework. Infine, seleziona "QuartzCore" dall'elenco dei framework disponibili e fai clic su "Aggiungi". Il risultato di questo processo è visualizzato visivamente di seguito:

Passaggio 5: sottoclasse LeavesViewController

Per il nostro progetto, vogliamo che il lettore entri immediatamente nel Guerra dei mondi testo senza una pagina di lander. Per fare questo, dovremo fare il WOTWViewController la classe eredita dal LeavesViewController classe invece di direttamente da UIViewController. Fallo aprendo WOTWViewController.h e modificando la dichiarazione dell'interfaccia come segue:

 @interface WOTWViewController: LeavesViewController 

La riga 1 sopra modifica WOTWViewController da ereditare da LeavesViewController invece di direttamente da UIViewController. Perché LeavesViewController da se stesso UIViewController, puoi pensare al WOTWViewController come il nipote di UIViewController

Quindi, cosa otteniamo per il nostro problema? LeavesViewController è conforme all'origine dati Leaves e ai protocolli delegati (discussi in seguito) e definisce personalizzati -loadview e -viewDidLoad implementazioni che aggiungono un tipo speciale di UIView chiamato a LeavesView alla gerarchia della vista corrente. Il LeavesView la classe è responsabile della maggior parte del lavoro dietro l'animazione del ricciolo della pagina.

Passaggio 6: aggiungere istruzioni di importazione necessarie

In ordine per il WOTWViewController classe per essere in grado di ereditare dal LeavesViewController classe, abbiamo bisogno di importare il LeavesViewController codice. Aggiungi i seguenti due #importare linee a WOTWViewController.h:

 #import "Utilities.h" #import "LeavesViewController.h"

Ti chiedi cosa Utilities.h la dichiarazione di importazione è per? Come vedremo più avanti, il progetto Leaves si basa su una funzione intelligente dichiarata in quel file chiamato aspectFit. Molti progetti Cocoa-Touch mantengono una classe Utilities per dichiarare e definire il codice helper utilizzato in tutta l'applicazione.

Passaggio 7: dichiarare i membri dei dati WOTW

Per ora, dovremo dichiarare un solo membro di dati per il nostro progetto. Nel WOTWViewController.h file, aggiungi la seguente riga di codice:

 CGPDFDocumentRef bookPDF;

Useremo "bookPDF" come riferimento al WOTW.pdf file più tardi. Il CGPDFDocumentRef il tipo variabile verrà ampiamente utilizzato in questo tutorial e merita un'ulteriore esplorazione nella documentazione ufficiale di Apple.

Passaggio 8: Inizializza foglie

Quando il WOTWViewController viene creato abbiamo bisogno di inizializzare il bookPDF membro dei dati dichiarato sopra. Come dimostrato nel progetto di esempio Leaves, puoi farlo con le seguenti linee di codice:

 - (id) init if (self = [super init]) CFURLRef pdfURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("WOTW.pdf"), NULL, NULL); bookPDF = CGPDFDocumentCreateWithURL ((CFURLRef) pdfURL); CFRelease (pdfURL);  return self; 

Vedi un problema con l'approccio sopra? Ricorda che stiamo caricando il nostro controller di visualizzazione da Interface Builder.

Il progetto di esempio Leaves presuppone che verrà creato manualmente a LeavesViewController istanza programmaticamente chiamando il -(Id) init metodo, così:

 WOTWViewController * viewController = [[[WOTWViewController alloc] init];

Tuttavia, nel nostro progetto vogliamo annullare l'archiviazione del WOTWViewController dal nostro Interface Builder NIB, quindi l'abitudine -(Id) init la funzione appena implementata non verrà mai chiamata. Invece, dobbiamo fornire un'implementazione personalizzata per il -(Id) initWithCoder: metodo per collegarsi al processo di annullamento dell'archiviazione NIB ed eseguire l'inizializzazione personalizzata. È bello lasciare il dentro in posizione in modo da avere la possibilità di creare questo controller di visualizzazione manualmente, ma dovremmo creare un nuovo metodo per l'inizializzazione del PDF e chiamare quel metodo da entrambi -(Id) init e -(Id) initWithCoder:.

Aggiungi la seguente riga di codice al WOTWViewController.h file:

 -(Vuoto) loadPDF;

Quindi, passare a WOTWViewController.m e implementare il metodo come segue:

 -(void) loadPDF CFURLRef pdfURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("WOTW.pdf"), NULL, NULL); bookPDF = CGPDFDocumentCreateWithURL ((CFURLRef) pdfURL); CFRelease (pdfURL); 

Infine, chiama il loadPDF metodo dagli inizializzatori di classe:

 - (id) init self = [super init]; if (self) [self loadPDF];  return self;  - (id) initWithCoder: (NSCoder *) aDecoder self = [super initWithCoder: aDecoder]; if (self) [self loadPDF];  return self; 

Quando il nostro controller di visualizzazione personalizzato non è archiviato, il -(Id) initWithCoder: il metodo verrà chiamato e chiamerà quindi loadPDF metodo.

C'è solo un'altra cosa. Avendo allocata memoria per il bookPDF riferimento, dovremmo anche rilasciare quella memoria quando avremo finito. Possiamo farlo aggiungendo la seguente riga di codice al -(Void) dealloc: metodo:

 CGPDFDocumentRelease (bookPDF);

Passaggio 9: Implementare il Leaves DataSource

Ricordiamo dal punto 5 che il LeavesViewController la classe aggiunge automaticamente un'istanza di LeavesView classe alla gerarchia della vista. Il LeavesView la classe ha in qualche modo bisogno di scoprire quale contenuto dovrebbe essere visualizzato nella vista, e ciò si ottiene chiamando due metodi di origine dati personalizzati: -(NSUInteger) numberOfPagesInLeavesView: e -(Void) renderPageAtIndex:.

Per fornire un'implementazione personalizzata per questi, apri WOTWViewController.m e aggiungi le seguenti righe di codice:

 #pragma mark LeavesViewDataSource methods - (NSUInteger) numberOfPagesInLeavesView: (LeavesView *) leavesView return CGPDFDocumentGetNumberOfPages (bookPDF);  - (void) renderPageAtIndex: (NSUInteger) indice inContext: (CGContextRef) ctx CGPDFPageRef page = CGPDFDocumentGetPage (bookPDF, index + 1); CGAffineTransform transform = aspectFit (CGPDFPageGetBoxRect (pagina, kCGPDFMediaBox), CGContextGetClipBoundingBox (ctx)); CGContextConcatCTM (ctx, transform); CGContextDrawPDFPage (ctx, page); 

Il -(NSUInteger) numberOfPagesInLeavesView: il metodo indica semplicemente quante pagine del contenuto LeavesViewController è responsabile della visualizzazione. Se stavi generando il contenuto per Leaves manualmente o se sapessi esattamente quante pagine erano nel PDF, puoi riportarlo manualmente qui. Certo, è sempre meglio determinare quel numero in modo dinamico, e questo è esattamente ciò che il CGPDFDocumentGetNumberOfPages () la funzione fa.

Il -(Void) renderPageAtIndex: InContext: il metodo è responsabile per il disegno reale a CGContextRef dopo aver aggiunto prima il contenuto PDF nel contesto passato come CTX.

Test del codice

Costruisci ed esegui il progetto. Se tutto va bene, ora dovresti essere in grado di vedere il Guerra dei mondi copertina del libro ed essere in grado di sfogliare le pagine con l'animazione di arricciatura della pagina!

Il finale WOTWViewController.h il file dovrebbe assomigliare a questo:

 #importare  #importare  #import "Utilities.h" #import "LeavesViewController.h" @interface WOTWViewController: LeavesViewController CGPDFDocumentRef bookPDF;  - (void) loadPDF; @fine

E il finale WOTWViewController.m il file dovrebbe essere come segue:

 #import "WOTWViewController.h" @implementation WOTWViewController #pragma mark - Initialization / Memory Management - (id) init self = [super init]; if (self) [self loadPDF];  return self;  - (id) initWithCoder: (NSCoder *) aDecoder self = [super initWithCoder: aDecoder]; if (self) [self loadPDF];  return self;  - (void) loadPDF CFURLRef pdfURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("WOTW.pdf"), NULL, NULL); bookPDF = CGPDFDocumentCreateWithURL ((CFURLRef) pdfURL); CFRelease (pdfURL);  - (void) dealloc CGPDFDocumentRelease (bookPDF); [super dealloc];  #pragma mark - LeavesViewDataSource methods - (NSUInteger) numberOfPagesInLeavesView: (LeavesView *) leavesView return CGPDFDocumentGetNumberOfPages (bookPDF);  - (void) renderPageAtIndex: (NSUInteger) indice inContext: (CGContextRef) ctx CGPDFPageRef page = CGPDFDocumentGetPage (bookPDF, index + 1); CGAffineTransform transform = aspectFit (CGPDFPageGetBoxRect (pagina, kCGPDFMediaBox), CGContextGetClipBoundingBox (ctx)); CGContextConcatCTM (ctx, transform); CGContextDrawPDFPage (ctx, page);  @fine

Alternative alle foglie

Nella mia ricerca su Leaves mi sono imbattuto in numerosi progetti open source aggiuntivi che aggiungono animazioni di transizione simili a pagine. Se hai trovato interessante questo progetto, dovresti anche controllare:

  • FlipView - FlipBook come animazioni
  • HMGLTransitions - Giri di pagina OpenGL
  • Paperstack - OpenGL (Unreleased dal 30/08/2011 - Si spera presto!)

Lascia un commento qui sotto se desideri vedere un tutorial su uno dei progetti sopra!

Vuoi vedere di più?

Abbiamo fatto dei buoni progressi in questo tutorial. Ora possiamo interagire con il Guerra dei mondi PDF e l'animazione di arricciatura pagina aggiunge un tocco estetico all'eBook. Tuttavia, c'è ancora molto lavoro da fare prima che questa app sia pronta per il rilascio su App Store. Ad esempio, sarebbe fantastico se l'utente venisse automaticamente riportato all'ultima pagina a cui hanno accesso quando l'app si avvia e sarebbe anche molto bello avere un UISlider o un componente di interfaccia simile per saltare rapidamente tra le sezioni del libro. Altre funzioni utili potrebbero includere ricerca, evidenziazione del testo, sommario o segnalibri.

Voglio assicurarmi che i miei tutorial SDK per iOS riguardino argomenti a cui è interessata la community Mobiletuts +. Pensi che dovrei creare un eReader completo e condividere il mio codice sorgente? O forse ti piacerebbe vedere un tutorial su qualcosa di completamente diverso? Rispondi al sondaggio seguente e fammi sapere!

AGGIORNAMENTO 9/7/2011: il sondaggio è ora chiuso. Oltre il 60% degli intervistati ha espresso interesse a vedere più post sull'aggiunta di un sommario e / o su un UISlider e un tutorial sull'uso di un UISlider è stato pubblicato (link sotto).

Puoi anche inviare il tuo feedback al mio account Twitter (@markhammonds), anche se ammetto che normalmente uso Twitter solo quando non lavoro su progetti freelance o sto scrivendo tutorial, quindi potresti semplicemente contattarmi via e-mail.

Clicca qui per leggere la seconda parte di questa serie