以下の実装ではページ数の多いPDFでは全ページのサムネイルを作り終えるまで応答がなくなるので操作性に問題があり、またサムネイル作成中にメモリ不足になっても回復不能でアプリが落ちてしまいます。この改善方法についてはPDFサムネイル表示改良版を参照してください。
手順概要
- 次のクラスを追加する。
- WebViewWithThumnails UIWebViewのサブクラス
サムネイル画像表示機能を追加するWebView - PdfThumbnailSrollVewi UIScrollViewのサブクラス
WebViewWithThumnailsに追加するサムネイル用スクロールビュー - PdfImageView UIControlのサブクラス
サムネイルを表示し、タップに応答するビュー - MyViewControllerのviewをWebViewWithThumnailsに変更
- WebViewWithThumnailsのdelegateにMyViewControllerをセット
- MyViewControllerにgoogleなどの検索画面を表示
- MyViewControllerのwebView:shouldStartLoadWithRequest:navigationType:メソッドでURLをチェックし、pdfファイルの場合は処理をトラップ
- NOを返す
- ファイルをダウンロード (ダウンロードファイルをNSDataで取得する方法参照)
- PDFファイルダウンロードが完了したら
- WebViewWithThumnailsにPDFを表示
- WebViewWithThumnailsにPdfThumbnailSrollVewi追加
- PdfThumbnailSrollVewiにサムネールイメージをセット
PDFファイルをダウンロードする手順はダウンロードファイルをNSDataで取得する方法を参照。
「受信終了」で呼ぶ [self self loadPdf]以降を例示。
@implementation MyViewController
//受信終了で呼び、ダウンロードした_dataをWebViewにロードする。
//PDFファイルダウンロード完了
- (void)connectionDidFinishLoading:(NSConnection*)connection;
{
_connection = nil;
[self loadPdf];
}
- (void)loadPdf
{
//PDFをUIWebViewに表示する
[ (WebViewWithThumbnails *)self.view loadData:_data
MIMEType:@"application/pdf"
[ (WebViewWithThumbnails *)self.view loadData:_data
MIMEType:@"application/pdf"
textEncodingName:@"utf-8"
baseURL:nil];
}
@end
@interface WebViewWithThumbnails : UIWebView
- (void)addThumbnailsWithData:(NSData *)pdfData;
@end
@implementation WebViewWithThumbnails
//オーバライド、superを呼んだ後にサムネールをセットする。
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
{
[self removeThumbnailScrollView];
[super loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL];
[super loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL];
[self addThumbnailsWithData:data];
}
//PDF以外の場合に呼ばれる。thumbnailScrollViewをremoveする。
//subviewsの中にThumbnailScrollViewオブジェクトがあればremoveする。
//PDF以外の場合に呼ばれる。thumbnailScrollViewをremoveする。
- (void)loadRequest:(NSURLRequest *)request
{
[self removeThumbnailScrollView];
[super loadRequest:request];
}
- (void)removeThumbnailScrollView
{
for(UIView *v in self.subviews) {
if ([v isMemberOfClass:[ThumbnailScrollView class]]) {
[v removeFromSuperview];
break;
}
}
}
//サムネールセット
- (void)addThumbnailsWithData:(NSData *)pdfData
{
[self removeThumbnailScrollView];
//画面下にUIScrollViewを追加
ThumbnailScrollView *thumbnailScrollView =
[[ThumbnailScrollView alloc] initWithWebView:self height:80];
//各ページサイズに合わせたThumbnailViewを追加
[thumbnailScrollView addThumbnailViews:pdfData];
//ThumbnailViewにイメージをセット
//ThumbnailViewにイメージをセット
[thumbnailScrollView setPdfThumbnailImage:pdfData];
}
@end
@interface ThumbnailScrollView : UIScrollView
- (ThumbnailScrollView *)initWithWebView:(UIWebView *)superview height:(float)height;
- (void)addThumbnailViews:(NSData *)pdfData;
- (void)setPdfThumbnailImage:(NSData *)pdfData;
@end
@implementation ThumbnailScrollView
{
//イメージセットが完了するまで保持する。
CGPDFDocumentRef _pdf;
}
//保持していた_pdfをreleaseする。
//setPdfThumbnailImageでイメージセット完了時にも実行しているが、
//その前にdeallocされる可能性があるのでここでも実行する。
- (void)dealloc
{
if (_pdf) CGPDFDocumentRelease(_pdf);
_pdf = nil;
}
//superviewにUIScrollViewを追加。frameはsuperviewに合わせて設定する。
- (ThumbnailScrollView *)initWithWebView:(UIWebView *)webView height:(float)height
{
//画面下10pt上の位置に設定。高さはパラメータの値、幅はsuperviewと同じ。
CGRect r = CGRectMake(0, webView.frame.size.height - height - 10,
webView.frame.size.width, height);
self = [super initWithFrame:r];
if (self) {
[webView addSubview:self];
}
return self;
}
//ScrollView内に、PDFページに対応するThumbnailImageViewを配置する。
//ここではまだイメージはセットしないが、矩形領域は表示されるようになる。
- (void)addThumbnailViews:(NSData *)pdfData
{
CGDataProviderRef provider =
CGDataProviderCreateWithCFData((__bridge CFDataRef)pdfData);
_pdf = CGPDFDocumentCreateWithProvider(provider);
//providerは同じメソッド内でreleaseしないとメモリリークの原因になる。
CFRelease(provider);
int numPages = CGPDFDocumentGetNumberOfPages(_pdf);
float x = 10;
float h = self.frame.size.height;
float pagePos = 0;
UIScrollView *webScrollView = ((UIWebView *)self.superview).scrollView;
for (int p = 1; p <= numPages; p++) {
//CGPDFPageRefはautoreleaseされるのでreleaseする必要なし。
CGPDFPageRef pageRef = CGPDFDocumentGetPage(_pdf, 1);
CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
float w = pageRect.size.width * (h / pageRect.size.height);
CGRect imageRect = CGRectMake(x, 0, w, h);
ThumbnailImageView *v = [[ThumbnailImageView alloc] initWithFrame:imageRect pageNum:p pagePos:pagePos];
v.alpha = 0.5;
[self addSubview:v];
//タップ時のアクションをセット
[v addTarget:self action:@selector(jumpToPage:) forControlEvents:UIControlEventTouchUpInside];
x += w + 10; //サムネイル間に10ptの間隔を置く。
pagePos += pageRect.size.height * (webScrollView.frame.size.width-5) / pageRect.size.width;
//contentSize調整
self.contentSize = CGSizeMake(self.contentSize.width + w + 10, self.contentSize.height);
}
[self setNeedsDisplay];
}
//配置したThumbnailImageViewにイメージをセット
- (void)setPdfThumbnailImage:(NSData *)pdfData
{
size_t numPages = CGPDFDocumentGetNumberOfPages(_pdf);
for(int p=1; p<=numPages; p++) {
CGPDFPageRef pageRef = CGPDFDocumentGetPage(_pdf, p);
ThumbnailImageView *v = [self.subviews objectAtIndex:p-1];
[v setImageWithPdfPage:pageRef];
}
//ループが無事完了したら_pdfをリリース
//ループが無事完了したら_pdfをリリース
CGPDFDocumentRelease(_pdf);
_pdf = nil;
[self setNeedsDisplay];
}
//タップされたサムネールのページ位置に移動
- (void)jumpToPage:(ThumbnailImageView *)sender
{
UIScrollView *scrollView = ((UIWebView *)self.superview).scrollView;
CGPoint point = CGPointMake(0, sender.pagePos * scrollView.zoomScale);
[scrollView setContentOffset:point animated:YES];
}
@end
0 件のコメント:
コメントを投稿