Ce tutoriel utilisera le projet open-source Leaves pour créer un lecteur iPad simple pour La guerre des mondes par H.G. Wells. En cours de route, nous examinerons rapidement le code du projet Leaves, discuterons des détails de la mise en œuvre et explorerons quelques options alternatives pour obtenir un effet similaire..
Leaves est un composant iOS à source ouverte qui simule une transition de page en tournant entre les vues de contenu, un peu comme la transition trouvée dans l'application iBooks officielle d'Apple. Le projet a été initialement écrit par Tom Brow et mis à disposition sur GitHub, où il a ensuite été créé par Ole Begemann pour permettre la prise en charge de mises en page de plusieurs pages..
Pour voir le projet Leaves en action, regardez la vidéo de démonstration suivante du projet que ce tutoriel vous apprendra à créer:
Bien entendu, l'effet de curling de page démontré ci-dessus n'est pas propre à cette démo ni à l'application iBooks. D'autres applications iOS natives (telles que l'application Cartes) utilisent également un effet similaire. Pour en savoir plus sur la manière dont Apple y parvient dans ses applications et pourquoi les développeurs de SDK iOS doivent recourir à un composant tel que Leaves, consultez les animations "App Store-Safe Page Curl" de Ole Begemann et "iBooks Dynamic Page Curl" de Apple. Steven Troughton-Smith.
Nous reviendrons plus tard sur une partie de la théorie derrière le projet Leaves, mais allons de l'avant et sautons dans la création de notre La guerre des mondes lecteur pour avoir une idée de l'apparence du code en action.
Le fichier de téléchargement joint à cet article Mobiletuts + contient le code source de Leaves et plusieurs ressources du domaine public (y compris le La guerre des mondes texte) utilisé dans le projet.
Ouvrez Xcode et créez un nouveau projet à l'aide du modèle "Application basée sur une vue". Nommez le projet "WOTW" et sélectionnez "iPad" dans le menu déroulant de la famille de périphériques..
Glissez-déposez les fichiers suivants dans le groupe "Fichiers de support" sous Xcode:
Tous les fichiers ci-dessus peuvent être trouvés dans le dossier "Ressources" du téléchargement joint à ce tutoriel..
Ensuite, ajoutez le code de composant Leaves réel. Créez un nouveau groupe appelé "Leaves" sous le dossier "WOTW" dans le navigateur de projet Xcode, puis faites glisser les fichiers suivants dans le groupe Leaves:
REMARQUE: Veillez à cocher la case "Copier les éléments dans le dossier du groupe de destinataires" lors de l'ajout des fichiers ci-dessus..
L'animation créée par Leaves dépend du Framework QuartzCore. Par conséquent, vous devrez associer ce cadre à votre projet pour que Leaves fonctionne. Pour ce faire dans Xcode 4, commencez par sélectionner "WOTW" dans le navigateur de projet. Ensuite, sélectionnez la cible "WOTW" puis l'onglet "Build Phases". Puis développez la liste déroulante "Link Binary With Libraries" et cliquez sur le symbole plus pour ajouter un nouveau framework. Enfin, sélectionnez "QuartzCore" dans la liste des infrastructures disponibles et cliquez sur "Ajouter". Le résultat de ce processus est affiché ci-dessous:
Pour notre projet, nous voulons que le lecteur se lance immédiatement dans La guerre des mondes texte sans page d'atterrisseur. Pour ce faire, nous devrons faire la WOTWViewController
classe hériter de la LeavesViewController
classe au lieu de directement de UIViewController
. Faites cela en ouvrant WOTWViewController.h et en modifiant la déclaration d'interface comme suit:
@interface WOTWViewController: LeavesViewController
La ligne 1 ci-dessus modifie WOTWViewController
hériter de LeavesViewController
au lieu de directement de UIViewController
. Parce que LeavesViewController
elle-même hérite de UIViewController
, vous pouvez penser à la WOTWViewController
en tant que petit-fils de UIViewController
Alors, qu'avons-nous pour nos ennuis? LeavesViewController
conforme à la source de données Leaves et aux protocoles de délégation (voir plus loin) et définit des paramètres personnalisés. -loadView
et -viewDidLoad
les mises en œuvre qui ajoutent un type spécial de UIView
appelé un LeavesView
à la hiérarchie de vue actuelle. le LeavesView
la classe est responsable de la majeure partie du travail derrière l'animation de la page.
Pour la WOTWViewController
classe pour pouvoir hériter de la LeavesViewController
classe, nous devons importer le LeavesViewController
code. Ajouter les deux suivants #importation
lignes à WOTWViewController.h:
#import "Utilities.h" #import "LeavesViewController.h"
Vous vous demandez ce que ça Utilitaires.h
déclaration d'importation est pour? Comme nous le verrons plus tard, le projet Leaves s’appuie sur une fonction intelligente déclarée dans ce fichier, appelée aspectFit
. De nombreux projets Cocoa-Touch gèrent une classe Utilities pour déclarer et définir le code d'assistance utilisé dans l'application..
Pour l'instant, nous n'aurons besoin que de déclarer un seul membre de données pour notre projet. dans le WOTWViewController.h fichier, ajoutez la ligne de code suivante:
CGPDFDocumentRef bookPDF;
Nous allons utiliser "bookPDF" comme référence au WOTW.pdf déposer plus tard. le CGPDFDocumentRef
le type de variable sera utilisé abondamment dans ce tutoriel et mérite une exploration plus poussée dans la documentation officielle d'Apple.
Quand le WOTWViewController
est créé, nous devons initialiser le bookPDF
membre de données déclaré ci-dessus. Comme illustré dans l'exemple de projet Leaves, vous pouvez le faire avec les lignes de code suivantes:
- (id) init if (self = [super init]) CFURLRef pdfURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("WOTW.pdf"), NULL, NULL); bookPDF = CGPDFDocumentCreateWithURL ((CFURLRef) pdfURL); CFRelease (pdfURL); retourner soi-même;
Voyez-vous un problème avec l'approche ci-dessus? N'oubliez pas que nous allons charger notre contrôleur de vue à partir d'Interface Builder..
Le projet exemple Leaves suppose que vous allez créer manuellement un LeavesViewController
exemple par programme en appelant le -(id) init
méthode, comme si:
WOTWViewController * viewController = [[[WOTWViewController alloc] init];
Cependant, dans notre projet, nous voulons désarchiver le WOTWViewController
de notre NIB Interface Builder, de sorte que la coutume -(id) init
fonction que nous venons de mettre en œuvre ne sera jamais appelée. Au lieu de cela, nous devons fournir une implémentation personnalisée pour le -(id) initWithCoder:
méthode afin de se connecter au processus unarchive NIB et effectuer une initialisation personnalisée. C'est bien de quitter le init
afin de pouvoir créer ce contrôleur de vue manuellement, mais nous devrions créer une nouvelle méthode pour l’initialisation PDF et appeler cette méthode à partir des deux. -(id) init
et -(id) initWithCoder:
.
Ajoutez la ligne de code suivante au WOTWViewController.h fichier:
-(vide) loadPDF;
Ensuite, passez à WOTWViewController.m et implémentez la méthode comme suit:
-(void) loadPDF CFURLRef pdfURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("WOTW.pdf"), NULL, NULL); bookPDF = CGPDFDocumentCreateWithURL ((CFURLRef) pdfURL); CFRelease (pdfURL);
Enfin, appelez le loadPDF
méthode de la classe d'initialisateurs:
- (id) init self = [super init]; if (self) [self loadPDF]; retourner soi-même; - (id) initWithCoder: (NSCoder *) aDecoder self = [super initWithCoder: aDecoder]; if (self) [self loadPDF]; retourner soi-même;
Lorsque notre contrôleur de vue personnalisé est désarchivé, le -(id) initWithCoder:
la méthode sera appelée et appellera ensuite le loadPDF
méthode.
Il n'y a plus qu'une chose. Ayant alloué de la mémoire pour le bookPDF
référence, nous devrions également libérer cette mémoire lorsque nous en avons terminé avec elle. Nous pouvons le faire en ajoutant la ligne de code suivante au -(vide) dealloc:
méthode:
CGPDFDocumentRelease (bookPDF);
Rappelez-vous de l'étape 5 que le LeavesViewController
la classe ajoute automatiquement une instance du LeavesView
classe à la hiérarchie de vue. le LeavesView
d’une manière ou d’une autre, la classe a besoin de savoir quel contenu doit être affiché dans la vue, en appelant deux méthodes de source de données personnalisées: -(NSUInteger) numberOfPagesInLeavesView:
et -(void) renderPageAtIndex:
.
Pour fournir une implémentation personnalisée pour ces derniers, ouvrez WOTWViewController.m et ajoutez les lignes de code suivantes:
#pragma mark Méthodes LeavesViewDataSource - (NSUInteger) numberOfPagesInLeavesView: (LeavesView *) leavesView return CGPDFDocumentGetNumberOfPages (bookPDF); - (void) renderPageAtIndex: (NSUInteger) index inContext: (CGContextRef) ctx CGPDFPageRef page = CGPDFDocumentGetPage (bookPDF, index + 1); CGAffineTransform transform = aspectFit (CGPDFPageGetBoxRect (page, kCGPDFMediaBox), CGContextGetClipBoundingBox (ctx)); CGContextConcatCTM (ctx, transform); CGContextDrawPDFPage (ctx, page);
le -(NSUInteger) numberOfPagesInLeavesView:
méthode indique simplement combien de pages de contenu la LeavesViewController
est responsable de l'affichage. Si vous générez manuellement le contenu des feuilles ou si vous savez exactement combien de pages se trouvent dans le fichier PDF, vous pouvez renvoyer ce nombre manuellement ici. Bien sûr, il est toujours préférable de déterminer ce nombre de manière dynamique, et c’est exactement ce que le CGPDFDocumentGetNumberOfPages ()
la fonction fait.
le -(void) renderPageAtIndex: inContext:
méthode est responsable de dessiner réellement un CGContextRef
après avoir ajouté le contenu PDF dans le contexte transmis en tant que ctx
.
Générez et exécutez le projet. Si tout se passe bien, vous devriez maintenant pouvoir voir le La guerre des mondes couverture du livre et être en mesure de parcourir les pages avec l'animation de page curl!
Le final WOTWViewController.h Le fichier devrait ressembler à ceci:
#importation#importation #import "Utilities.h" #import "LeavesViewController.h" @interface WOTWViewController: LeavesViewController CGPDFDocumentRef bookPDF; - (void) loadPDF; @fin
Et la finale WOTWViewController.m Le fichier doit se lire comme suit:
#import "WOTWViewController.h" @implementation WOTWViewController #pragma mark - Initialisation / Gestion de la mémoire - (id) init self = [super init]; if (self) [self loadPDF]; retourner soi-même; - (id) initWithCoder: (NSCoder *) aDecoder self = [super initWithCoder: aDecoder]; if (self) [self loadPDF]; retourner soi-même; - (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 - Méthodes LeavesViewDataSource - (NSUInteger) numberOfPagesInLeavesView: (LeavesView *) leavesView return CGPDFDocumentGetNumberOfPages (bookPDF); - (void) renderPageAtIndex: (NSUInteger) index inContext: (CGContextRef) ctx CGPDFPageRef page = CGPDFDocumentGetPage (bookPDF, index + 1); CGAffineTransform transform = aspectFit (CGPDFPageGetBoxRect (page, kCGPDFMediaBox), CGContextGetClipBoundingBox (ctx)); CGContextConcatCTM (ctx, transform); CGContextDrawPDFPage (ctx, page); @fin
Dans mes recherches sur les feuilles, je suis tombé sur plusieurs projets open source supplémentaires qui ajoutaient des animations de transition de type page. Si vous avez trouvé ce projet intéressant, vous devriez également vérifier:
Laissez un commentaire ci-dessous si vous souhaitez voir un tutoriel sur l'un des projets ci-dessus.!
Nous avons fait de bons progrès dans ce tutoriel. Nous pouvons maintenant interagir avec le La guerre des mondes PDF et l'animation de page curling ajoute une grande sensation esthétique à l'eBook. Cependant, il reste encore beaucoup de travail à faire avant que cette application soit prête à être publiée sur l'App Store. Par exemple, il serait intéressant que l'utilisateur revienne automatiquement à la dernière page à laquelle il a accédé lors du lancement de l'application. Il serait également très agréable d'avoir un UISlider
ou un composant d'interface similaire pour sauter rapidement entre les sections du livre. D'autres fonctionnalités utiles peuvent inclure la recherche, la mise en surbrillance du texte, une table des matières ou des signets..
Je veux m'assurer que mes tutoriels iOS SDK couvrent des sujets qui intéressent la communauté Mobiletuts +. Pensez-vous que je devrais créer un eReader à part entière et partager mon code source? Ou peut-être aimeriez-vous voir un tutoriel sur quelque chose de complètement différent? Répondez au sondage suivant et faites le moi savoir!
UPDATE 9/7/2011: Le sondage est maintenant fermé. Plus de 60% des répondants ont exprimé le souhait de voir plus de publications sur l'ajout d'une table des matières et / ou d'un UISlider et un tutoriel utilisant un UISlider a été publié (lien ci-dessous)..
Vous pouvez également envoyer vos commentaires sur mon compte Twitter (@markhammonds), bien que j'admette que je n'utilise généralement Twitter que lorsque je ne travaille pas sur des projets indépendants ou que je ne rédige pas de tutoriels. Vous pouvez donc simplement me contacter par e-mail..