Archive

Posts Tagged ‘PDF’

Displaying a PDF file within an App…

July 24, 2013 Leave a comment

As part of the app I am working on I wanted to use a PDF document for the help file. I am using a storyboard and the help displays in a separate view. Since the help document contains multiple pages I wanted to allow the user to be able to navigate through the document using swipe gestures.

This is what I ended up with:

Since I learned so much about how to do this from various places on the Internet, I thought I’d return the favor and show my code. I am sure it could be improved a lot (I am a noob at this Objective-C stuff after all) and I’ll probably cringe if I come back to this in six months but regardless, I offer my code in the hope that it may be of use to someone. Oh, and if you spot any REALLY BAD errors, feel free to let me know. I’m not proud at all and always willing to learn.

My screen consists of a navigation bar with the ‘Done’ button (btnHelpDone) on it and a UIView (pdfView) that fills the rest of the screen. There are also four swipe gesture controllers, one for each direction. The ‘Done’ button just closes the current view and returns to the previous one in the storyboard.

I replaced the UIView’s drawRect with my own which does the bulk of the work to display the PDF.

This the he helpViewController.h file…

//
//  HelpViewController.h
//
//  Created by David Ellis on 2013-07-14.
//  Copyright (c) 2013 David Ellis. All rights reserved.
//

#import <UIKit/UIKit.h>

// see drawHelp
extern NSInteger g_helpDocPageNum;
extern CGPDFDocumentRef g_helpDocRef; 
extern NSInteger g_helpDocMaxPage;

@interface HelpViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIView *pdfView;
- (IBAction)btnHelpDone:(id)sender;
- (IBAction)helpLeftSwipe:(id)sender;
- (IBAction)helpRightSwipe:(id)sender;
- (IBAction)helpUpSwipe:(id)sender;
- (IBAction)helpDownSwipe:(id)sender;

@end

This is the helpViewController.m file

//
//  HelpViewController.m
//
//  Created by David Ellis on 2013-07-14.
//  Copyright (c) 2013 David Ellis. All rights reserved.
//

#import "HelpViewController.h"

@interface HelpViewController  ()

@end

@implementation HelpViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    // self.pdfView.backgroundColor = [UIColor redColor];   // test just to show this code runs
    // NSLog(@"helpviewdidload");

   }

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)btnHelpDone:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)helpLeftSwipe:(id)sender {
    // next page
    // NSLog(@"helpLeftSwipe");
    if (g_helpDocPageNum < g_helpDocMaxPage) {
        g_helpDocPageNum=g_helpDocPageNum+1;

        [UIView transitionWithView:self.pdfView duration:1
            options:UIViewAnimationOptionTransitionCurlUp      
            animations:^{
            //     [self.pdfView.layer displayIfNeeded];
            }  completion:nil];

        [self.pdfView  setNeedsDisplay];
    }
}

- (IBAction)helpRightSwipe:(id)sender {
    // prev page
    // NSLog(@"helpRightSwipe");
    if (g_helpDocPageNum > 1) {
        g_helpDocPageNum = g_helpDocPageNum-1;

        [UIView transitionWithView:self.pdfView duration:1
            options:UIViewAnimationOptionTransitionCurlDown
            animations:^{
           //     [self.pdfView.layer displayIfNeeded];
            }  completion:nil];

        [self.pdfView setNeedsDisplay];
    }
}

- (IBAction)helpUpSwipe:(id)sender {
    // same as left swipe = next page
    // NSLog(@"helpUpSwipe");
    [self helpLeftSwipe:sender];
}

- (IBAction)helpDownSwipe:(id)sender {
    // same as right swipe = prev page
    // NSLog(@"helpDownSwipe");
    [self helpRightSwipe:sender];
}

- (void)viewDidUnload {
    [self setPdfView:nil];
    [super viewDidUnload];
}

@end

The helpViewController.m file implements the code to close the view when the Done button is pressed and the gesture controller code. The Up and down gesture code just calls the Left and Right code.

The pdfView UIview is sub classed to the drawHelp class. This is the drawHelp.h file (not much in it as you can see!):

//
//  drawHelp.h
//
//  Created by David Ellis on 2013-07-15.
//  Copyright (c) 2013 David Ellis. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface drawHelp : UIView

@end

And finally, the drawHelp.m class file:

//
//  drawHelp.m
//
//  Created by David Ellis on 2013-07-15.
//  Copyright (c) 2013 David Ellis. All rights reserved.
//

#import "drawHelp.h"

CGPDFDocumentRef g_helpDocRef=NULL;
NSInteger g_helpDocPageNum=1;
NSInteger g_helpDocMaxPage=0;

@implementation drawHelp

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

CGPDFDocumentRef MyGetPDFDocumentRef (NSString *filename)
{

    CGPDFDocumentRef document;
    size_t count;

    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType :@"pdf"];
    NSURL *url = [NSURL fileURLWithPath:path];

    document = CGPDFDocumentCreateWithURL ((__bridge CFURLRef)url);

    count = CGPDFDocumentGetNumberOfPages (document);
    if (count == 0) {
        NSLog(@"`%@' needs at least one page!", filename);
        return NULL;
    }

    return document;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{

    // Drawing code

    CGPDFPageRef page;

    // NSLog(@"This is drawRect");

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // set background color
    CGContextSetRGBFillColor(ctx, 255.0, 255.0, 255.0, 1.0);
    CGContextFillRect(ctx,rect);

    // flip co-ordinates for pdf
    CGContextGetCTM(ctx);
    CGContextScaleCTM(ctx,1,-1);
    CGContextTranslateCTM(ctx,0,-rect.size.height);

    g_helpDocRef=MyGetPDFDocumentRef(@"Help");
    g_helpDocMaxPage=CGPDFDocumentGetNumberOfPages(g_helpDocRef);
    page = CGPDFDocumentGetPage(g_helpDocRef,g_helpDocPageNum);

    CGRect cropRect = CGPDFPageGetBoxRect(page,kCGPDFCropBox);
    CGContextScaleCTM(ctx, rect.size.width / cropRect.size.width, rect.size.height/ cropRect.size.height);
    CGContextTranslateCTM(ctx,-cropRect.origin.x,-cropRect.origin.y);

    CGContextDrawPDFPage(ctx,page);

    CGPDFDocumentRelease(g_helpDocRef);

}

@end

Some global variables (prefixed g_) keep track of the pdf reference, the current page number and the max page number (I’m sure I should be doing those differently but this works for now).

The MyGetPDFDocumentRef routine loads the pdf and returns a reference to it.

The drawRect function function sets up the UIview background color, flips the co-ordinate system for the pdf display, loads the pdf and draws the current page.

You’ll notice that the drawRect function has nothing to do with the paging or the curlup/down animation. That is all handled by the swipe gesture controllers up in the helpViewController.m file. In case it is confusing, a swipe to the right means you want to go BACK a page so the right swipe handler reduces the page number (provided it does not go below 1) while a swipe to the left means you want to go to the next page so it adds one to the page number provided it does not exceed the number of pages in the document.

The gesture controller then sets up the animation (curl up or curl down) and initiates a redraw of the pdfView UIView using [self.pdfView setNeedsDisplay] which triggers the drawRect code to display whatever page is currently selected. iOS handles the actual curl up./down animation.

Categories: Coding, iPhone, xcode Tags: , ,