Construire un lecteur iPad pour la guerre des mondes

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

À propos du projet feuilles

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.

Construire le PDF Reader WOTW

Étape 1: Téléchargez les ressources du projet

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.

Étape 2: Créer un nouveau projet Xcode

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

Étape 3: Ajouter les ressources du projet à Xcode

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:

  • Utilitaires.h
  • Utilitaires.m
  • LeavesCache.h
  • LeavesCache.m
  • LeavesView.h
  • LeavesView.m
  • LeavesViewController.h
  • LeavesViewController.m

REMARQUE: Veillez à cocher la case "Copier les éléments dans le dossier du groupe de destinataires" lors de l'ajout des fichiers ci-dessus..

Étape 4: Liez le cadre QuartzCore

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:

Étape 5: Sous-classe LeavesViewController

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.

Étape 6: Ajouter les instructions d'importation nécessaires

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

Étape 7: Déclarez les membres de données WOTW

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.

Étape 8: Initialiser les feuilles

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

Étape 9: Implémentation de la source de données Leaves

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.

Tester le code

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

Alternatives aux feuilles

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:

  • FlipView - FlipBook comme des animations
  • HMGLTransitions - Tours de page OpenGL
  • Paperstack - OpenGL (Inédit le 30/08/2011 - bientôt disponible!)

Laissez un commentaire ci-dessous si vous souhaitez voir un tutoriel sur l'un des projets ci-dessus.!

Veux tu en voir plus?

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

Cliquez ici pour lire la deuxième partie de cette série