It is possible to use JavaScript to set the pixel y-offset of a UIWebView
, e.g.:
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"scrollTo(0, %d)", offset]];
So is there a way to get:
- The pixel height of an individual page of a PDF within the web view?
- The size of the gap between pages?
Is this information available from the UIWebView
or can it be calculated through alternative means?
I'm thinking that if I have the number of pages (via CGPDFDocumentGetNumberOfPages
), the pixel height gap between pages, or the pixel height of an individual page, I can calculate the offset
to use with the JavaScript call. Then I just wire up a UIButton
or UISlider
to move between pages.
EDIT I
I have a solution, but it uses UIWebDocumentView
, a private subview of UIWebView
.
I create a view controller called PDFViewerViewController
, which is a subclass of WebViewerViewController
, which itself is a view controller that contains a UIToolbar
, a UIWebView
, and conforms to the UIWebViewDelegate
protocol.
My PDFViewerViewController
calculates some information about the enclosing web view and the PDF data, after the web view delegate method -webViewDidFinishLoad:
gets called.
This information is used to calculate an approximate per-page offset that gets fed to the web view via JavaScript.
PDFViewerViewController.h
#import <UIKit/UIKit.h>
#import "WebViewerViewController.h"
@interface UIWebDocumentView : NSObject {}
@end
@interface PDFViewerViewController : WebViewerViewController {
NSUInteger offset;
NSUInteger currentPage;
NSUInteger documentPages;
CGFloat documentHeight;
CGFloat pageHeight;
}
@property (assign) NSUInteger offset;
@property (assign) NSUInteger currentPage;
@property (assign) NSUInteger documentPages;
@property (assign) CGFloat documentHeight;
@property (assign) CGFloat pageHeight;
@end
PDFViewerViewController.m
#import "PDFViewerViewController.h"
@implementation PDFViewerViewController
@synthesize offset;
@synthesize currentPage;
@synthesize documentPages;
@synthesize documentHeight;
@synthesize pageHeight;
- (void) viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *_leftArrow = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ArrowLeft.png"] style:UIBarButtonItemStylePlain target:self action:@selector(leftArrow:)];
UIBarButtonItem *_flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *_rightArrow = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ArrowRight.png"] style:UIBarButtonItemStylePlain target:self action:@selector(rightArrow:)];
[[super.viewerToolbarView toolbar] setItems:[NSArray arrayWithObjects:_leftArrow, _flexibleSpace, _rightArrow, nil]];
[_leftArrow release];
[_flexibleSpace release];
[_rightArrow release];
self.currentPage = 0;
}
- (void) webViewDidFinishLoad:(UIWebView *)_webView {
for (UIView *_subview in [[[_webView subviews] objectAtIndex:0] subviews]) {
if ([_subview isKindOfClass:[UIWebDocumentView class]]) {
self.documentHeight = _subview.bounds.size.height;
}
}
CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL((CFURLRef)baseURL);
self.documentPages = CGPDFDocumentGetNumberOfPages(pdfDocument);
CGPDFDocumentRelease(pdfDocument);
self.pageHeight = (self.documentHeight + (10 * self.documentPages)) / self.documentPages;
self.currentPage = 1;
self.offset = 0;
}
- (void) leftArrow:(id)_param {
if (self.currentPage == 1)
return;
self.offset -= (NSUInteger)self.pageHeight;
self.currentPage--;
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"scrollTo(0, %d)", (self.offset * 2)]];
}
- (void) rightArrow:(id)_param {
if (self.currentPage == self.documentPages)
return;
self.offset += (NSUInteger)self.pageHeight;
self.currentPage++;
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"scrollTo(0, %d)", (self.offset * 2)]];
}
Some observations
The offset calculation isn't page-perfect. If the PDF document isn't 8.5 x 11 (e.g. A4) then the offset error gets worse more quickly.
The
self.currentPage
property doesn't get updated when scrolling through the web view by way of touch-drag. One might drag a few pages, and then touching the left or right arrow on the toolbar will cause the offset to unexpectedly move to a previous page.This solution uses
UIWebDocumentView
, which is private and may likely cause app rejection.
I think I'll file a feature enhancement request with Apple.
Has anyone built a non-UIWebView
-based PDF viewer (with source code)?
-webViewDidFinishLoad:
, I get values that do not reflect the actual height of the content. (For example, for a four-page PDF, I should get something much more than 456 pixels for a PDF displayed in portrait orientation.) – Mcginty