iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
前回のサンプル・プログラムをリソースとして持っているPDF文書からページ数を取得して、頁に対応したページを表示するように拡張する。
Page-Based Applicationの雛形は、データを管理するクラスModelControllerが用意されている。また、iOSには複数の文書を扱う仕組みが用意されているので、いずれは、それへの対応という事になるが、今回は自分が単一文書を扱う場合に用意している独自のDocumentクラスでPDF書類を管理する事にした。
本当は、PDF文書の扱いはDocumentクラスで抽象化すべきと思うが、サンプル・コードという事で、単にプロパティとして持っている事で許して欲しい。
@interface Document : NSObject
…
@property (nonatomic, assign) CGPDFDocumentRef pdf;
…
@end
そして、各コントローラクラスで、Documentクラスをプロパティとして参照するようにする。例えば、初期化をinitメソッドで行う場合は、以下のとおり。
#import "AppDelegate.h"
…
- (id)init
{
self = [super init];
if (self) {
AppDelegate *appl = nil;
appl = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.document = appl.document;
}
return self;
}
ページ・ビュー・コントローラの利用では、各クラスの関係や、モデルの初期化のタイミングは少し悩んだので、分かりやすいように掻い摘んで説明する。
ADCのサンプルZoomingPDFViewでは、決めうちで、リソースで持っているPDF文書の1頁だけを表示するに固定されているので、PDFScrollViewの初期時にPDF文書関連の初期化を行っていたが、それを止めて、外部から指定されたタイミングで指定された頁を表示する様に変更する。
@interface PDFScrollView : UIScrollView
…
- (void)setIndexOfPDF:(NSUInteger)index;
- (NSUInteger)getIndexOfPDF;
…
@end
@implementation PDFScrollView
…
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)awakeFromNib
{
self.decelerationRate = UIScrollViewDecelerationRateFast;
self.delegate = self;
AppDelegate *appl = nil;
appl = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.document = appl.document;
}
- (void)setIndexOfPDF:(NSUInteger)index
{
self.page = CGPDFDocumentGetPage(self.document.pdf, index + 1);
CGPDFPageRetain(self.page);
CGRect pageRect = CGPDFPageGetBoxRect(self.page, kCGPDFMediaBox);
self.pdfScale = self.frame.size.width/pageRect.size.width;
pageRect.size = CGSizeMake(pageRect.size.width * self.pdfScale, pageRect.size.height * self.pdfScale);
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextScaleCTM(context, self.pdfScale, self.pdfScale);
CGContextDrawPDFPage(context, self.page);
CGContextRestoreGState(context);
UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
self.backgroundImageView.frame = pageRect;
self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:self.backgroundImageView];
[self sendSubviewToBack:self.backgroundImageView];
self.pdfView = [[TiledPDFView alloc] initWithFrame:pageRect andScale:self.pdfScale];
[self.pdfView setPage:self.page];
[self addSubview:self.pdfView];
}
- (NSUInteger)getIndexOfPDF
{
return (NSUInteger)CGPDFPageGetPageNumber(self.page);
}
…
@end
雛形ではカレンダーのデータを保持していたDataViewControllerクラスを表示している頁番号とPDFScrollViewクラスを扱うように変更する。
@interface DataViewController : UIViewController
…
@property (strong, nonatomic) Document *document;
@property (nonatomic, assign) NSUInteger index;
…
- (void)setIndexOfPDF:(NSUInteger)index;
- (NSUInteger)getIndexOfPDF;
@end
@implementation DataViewController
…
- (void)setIndexOfPDF:(NSUInteger)index
{
self.index = index;
PDFScrollView *pdfScrollView = (PDFScrollView *)self.view;
[pdfScrollView setIndexOfPDF:index];
}
- (NSUInteger)getIndexOfPDF
{
return self.index;
}
…
@end
頁に対応するビュー・コントローラDataViewControllerは、モデル・コントーラで管理される?ということで、PDF表示に対応させる。
@implementation ModelController
…
- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
if (CGPDFDocumentGetNumberOfPages(self.document.pdf) < index)
return nil;
DataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:@"DataViewController"];
[dataViewController setIndexOfPDF:index];
return dataViewController;
}
- (NSUInteger)indexOfViewController:(DataViewController *)viewController
{
return viewController.index;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(DataViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(DataViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == CGPDFDocumentGetNumberOfPages(self.document.pdf))
return nil;
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
…
@end
このサンプルをGitHubから取得して、実行すると、強制的に著者がCocoa勉強会で発表した文書を読まされる事になる。