Thursday, October 27, 2011

PDF in IOS without Navigation Controller

Another sample of the Art of Rolf from Elmore!  If you like his stuff head over to his site and have a look.  All art in Rolf is used under license.

In the creation of Rolf! I wanted to add the paper game rule book to the game.  The format of the book is PDF and I though it should be no problem.  After much googling (please no Binging,  That does not EVEN sound right does it?) I found that there are several ways to go.  A lot of folks used a web view and let webkit do the rendering.  That was ok, but things did not look like I wanted.  Also I wanted to be able to print or add it to iBooks.   The Document Interaction framework seemed to be a perfect fit.  It was but there was a hitch.

First  here is the code when the rule button is pressed:

  if(self.docController == nil)
        UIDocumentInteractionController *dc = [UIDocumentInteractionController interactionControllerWithURL:url];
        dc.delegate = self;
        self.docController = dc;

   [self.docController presentPreviewAnimated:YES];

This worked perfectly.  The PDF is shown in its own view.  A menu of supported operations is present.  Perfect,  except when you hit the provided DONE button it crashed.

Hmmm  What delegate method gets called when the done button is pressed.  This is the tricky part.  According to the apple documentation on presentPreviewAnimated
This method displays the document preview asynchronously. The document interaction controller dismisses the document preview automatically in response to appropriate user interactions. You can also dismiss the preview programmatically using the dismissPreviewAnimated: method.

So over to the delegate protocol ( UIDocumentInteractionControllerDelegate) docs.

So you Must implement this Optional Method!
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller

I know, pretty intuitive huh!  Here is the passage from the docs:

Although technically optional, this method is required if your application attempts to display a preview for a document. The view controller returned by this method is used as the parent for the document preview.
Hmm does not sound Optional.

Ok so now what happens when you are done with the preview and hit the DONE button?

Again from the docs:

If you return a navigation controller from this method, the document interaction controller is pushed onto the navigation stack using the standard navigation controller animations. If you return any other type of view controller, the document interaction controller is displayed modally, in which case, the view controller you return must be capable of presenting a modal view controller.

In Rolf!  I am not using a Nav controller to move between views.  I did not want to give up the real-estate and wanted better control over the navigation.  So I thought COOL.  All views are capable of modal transitions.  NO Problem. The Preview IS presented modally.   Nope I was wrong.  After looking through the views in the debugger, I found that several properties on the view were nil.

Long story short Modifing my code to:

 if(self.docController == nil)
        UIDocumentInteractionController *dc = [UIDocumentInteractionController interactionControllerWithURL:url];
        dc.delegate = self;
        self.docController = dc;
    self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

   [self.docController presentPreviewAnimated:YES];

Did the trick.  Notice the next to the last line!  That was it!

Happy Coding!

1 comment: