Absolute Ripple
  • Absolute Ripple
  • Contact

Printing documents, images, etc in iOS

25/3/2012

0 Comments

 
Once you have implemented the ability to open a files in another app using the UIDocumentInteractionController (as described in the previous post), it doesn't take that much effort to enable printing. You essentially only need to implement two further methods in the UIDocumentInteractionController delegate protocol. (The following assume that you have already implemented UIDocumentInteractionController as described in the previous post.)
The additional codes are:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action
{
    if (action == @selector (print:) &&
        [UIPrintInteractionController canPrintURL: controller.URL]) {
        return YES;
    } else {
        return NO;
    }
}

- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller performAction:(SEL)action
{
    bool __block success = NO;
    if (action == @selector(print:)) {
        UIPrintInteractionController *printController = [UIPrintInteractionController sharedPrintController];
        printController.printingItem = controller.URL;
        [printController presentAnimated:YES
                       completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error){
                           if (completed) {
                               success = YES;
                           } else {
                            NSLog(@"The print job did not complete.");
                           }
                       }];
    }
    return success;
}

The first method tells the UIDocumentInteractionController whether certain actions can be performed in respect of the document. The default response is 'NO'. In this case, we are telling the controller that printing is supported.
The second method is called by the controller when it wants its delegate to perform a particular action, such as printing action here.
Both of these methods make use of a class called UIPrintInteractionController, which handles the printing for you. All you need to do (as done above) is to pass it the document's url.


0 Comments

Opening files in another app

19/3/2012

4 Comments

 
It is relatively simple to get another app (a third party or one of Apple's apps) on the iPhone or iPad to open a file. The magic is mostly done by Apple in the UIDocumentInteractionController Class.
This class is part of the UIKit framework, which is included by the default xCode project setup so there is no need to link any additional framework.
This is what you need to do in terms of code:
1. Make your relevant class file conform to the UIDocumentInteractionControllerDelegate protocol and define a variable
Assuming your class is called ViewController, then in the ViewController.h file:
        @interface ViewController : UIViewController <UIDocumentInteractionControllerDelegate>
        {
            UIDocumentInteractionController *docController;
        }
2. Add the following methods in ViewController.m:
        //- set up the UIDocumentInteraction controller and set its delegate to self so we can handle the callback events
        - (UIDocumentInteractionController *) setupControllerWithURL:(NSURL *)fileURL
                                               usingDelegate:(id <UIDocumentInteractionControllerDelegate>)         interactionDelegate {
   
            UIDocumentInteractionController *interactionController =
            [UIDocumentInteractionController interactionControllerWithURL:fileURL];
            interactionController.delegate = interactionDelegate;
   
            return interactionController;
            }
       
        //- the key instance method here is the presentOptionsMenuFromBarBUttonItem
        //- it is assumed here that there is a BarButtonItem called _btnActions
        - (void)showOptionsMenu
        {
            NSURL *fileURL = [NSURL fileURLWithPath:@"THE_FILE_URL_PATH"];
            docController = [self setupControllerWithURL:fileURL
                                   usingDelegate:self];
            bool didShow = [docController presentOptionsMenuFromBarButtonItem:_btnActions
                                                             animated:YES];
            if (!didShow) {
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"Sorry. The appropriate apps are not found on this device."
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles: nil];
                    [alert show];
            }
        }
3. Add a method to invoke the above when you want to show the apps that you could send the file to
In this example, a UIBarButton is wired up to the following IBActions:
    - (IBAction)ActionButtonClicked:(id)sender {
        [self showOptionsMenu];
    }
That is it. When the button is clicked an action sheet will appear (all powered by the Apple's UIDocumentInteractionController class) that shows the apps (if any) that you could send the file to.

You can optionally implement the following delegate methods:
- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller
4 Comments

Generating PDF in iOS

15/3/2012

0 Comments

 
The ability to export a PDF document, created using data generated through the app, can be a useful feature to have in an app.  There are a number of ways to create the PDF:
(i) External way - the PDF document can be created with the help of a server. In this case, the app simply send the data (suitably structured) to a server which generates the PDF file using some server side script. Once the file is generated, it can be sent back to the app for further actions, such as forwarding it via email to someone. Indeed, the server could send the file directly to whomever.
(ii) Internal way - the PDF document is generated within the app on the iPhone or iPad (without involving an external server).
Which way is better depends on your requirements. The involvement of a server is sometimes necessary if you need to combine external data to create the PDF document. An external server may be more efficient if the document is complex or large.
This note is about the internal way.
Generating PDF directly on the iPhone and iPad
PDF document can be created in iOS. The Quartz 2D drawing engine is developed with PDF document creation, display and parsing in mind. The process of creating a PDF document is perhaps not as obvious as other things in iOS, but it is certainly not difficult and you can create nice looking document just by knowing a few things.
There are two ways to generate a PDF document on iOS:
(i) Use Core Graphics functions; and
(ii) Use UIKit framework.
The UIKit framework is certainly much easier to use that calling Core Graphics functions, but the latter could be more flexible and powerful. Again, the better approach depends on your requirements and it can be matter of personal taste.
This is an excellent online tutorial: Generate PDF programmatically in iPhone/iPad SDK. It shows you how to draw lines, border, text and image.
For those who like to write even less code and leverage the graphical user interface of Interface Builder, you can use UILabel to display text on the PDF document. Here is how.
A Simple Example
This example creates a landscape page with an image on the left and some text on the right hand side.
1. Create a UILabel object in Interface Builder. i.e. simply drag a UILabel object onto the view controller in Interface Builder.
2. Create the setter and getter for this label in the class files of the view controller using the standard @property and @synthesize technique, i.e.
        @property (strong, nonatomic) IBOutlet UILabel *textLabel;
        @synthesize textLabel = _textLabel;
(Remember to connect this to the actual UILabel in Interface Builder. As an aside, it is quite easy to forget to do this, at least I often do. This is why I prefer to let xCode creates the @property and @syntheize code automatically by using the 'control click and point' technique. Another advantage of this approach is that xCode will add the relevant memory management code automatically too - one less thing to do).
3. Enter the following codes in viewDidLoad:
    // defines the path for the saved pdf file
    NSString *docDirectory =
        [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *pdfPath = [docDirectory stringByAppendingPathComponent:@"pdfFile.pdf"];

    // set the size of the page (the page is in landscape format)
    CGRect pageBounds = CGRectMake(0.0f, 0.0f, 792.0f, 612.0f);

    // sets the size and position of the image and text
    CGRect imageBounds = CGRectMake(30.0f, 50.0f, 500.0f, 375.0f);
    CGRect textBounds = CGRectMake(550.0f, 50.0f, 182.0f, 375.0f);

    // create an UIImage object using a photo named "sampleImage.jpg"
    UIImage *theImage = [UIImage imageNamed:@"sampleImage.jpg"];
    // set the text
    _textLabel.text = @"Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.";
   
    // create and save the pdf file
    UIGraphicsBeginPDFContextToFile(pdfPath, pageBounds, nil);
    {
        UIGraphicsBeginPDFPage();
        [theImage drawInRect:imageBounds];
       
        [_textLabel drawTextInRect:textBounds];
       
    }
    UIGraphicsEndPDFContext();

4. One final step. Select the UILabel in Interface Builder, and in the Attribute Inspector, make sure that the attributes are set with the following values:
    Lines: 0   (setting to zero means that it is unbounded)
    Line Breaks: Character Wrap
    Font: System 14.0  (you can use other size or font)
    Text Color: (use default or pick a color)

Run the code in the Simulator and the PDF file will be saved inside the app's Documents folder. You can then add code to email or do whatever you want with the PDF file.

Drawing an NSString directly to the pdf context is more flexible, but an advantage of using UILabel as describe here is that it allows you to change the font, size, style, color, etc graphically in Interface Builder. This can be quite useful when you want to knock up something fast. Doing similar using NSString requires more coding and, as far as I know, you cannot simple things like 'bolding' the text without using Core Text and NSAttributedString (which is not that friendly to use). Again, the better approach to use depend on your requirement.


0 Comments

Disbling the button that triggers the Popover View

10/3/2012

0 Comments

 
Scenario: You have created a popover view using iOS storyboard. The popover view is triggered by the clicking of a 'button' on the UINavigationBar or UIToolbar. Once the popover view appears, you can click outside of the popover view to dismiss it. But if you click the 'button' again, another popover view appear on top of the existing one. To dismiss the popover views, you need to click outside the popover view twice to dismiss it. (Indeed, more popover view will appear if you click the 'button' again.) Not a nice behavior to have.

Disable the 'button'.
You need to disable the 'button' when the segue is triggered and re-enable it when the user's click outside the popover view.

1. Create two accessors using the usual @property & @synthesize approach.
Under @interface,
    @property (strong, nonatomic) IBOutlet UIBarButtonItem *btnSettings;
    @property (strong, nonatomic) UIStoryboardPopoverSegue* popSegue;
Under @implementation,
    @synthesize btnSettings = _btnSettings;
    @synthesize popSegue = _popSegue;
(Remember to link up the actual button to the IBOutlet in Interface Builder.)

2. Make the viewcontroller confirms to the UIPopoverControllerDelegate protocol
    eg. @interface ViewController : UIViewController <UIPopoverControllerDelegate>

3. Inside the method (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    if ([segue.identifier isEqualToString:@"NAME_OF_YOUR_SEGUE"]) {
        //- for this purpose alone, you don't really need a popSegue property, but having a reference
        //- to the popover segue is useful
        self.popSegue = (UIStoryboardPopoverSegue *)segue;
        //- this gets the reference to the actual UIPopoverController which you need to set the delegate
        UIPopoverController *pc = [_popSegue popoverController];
        //- setting the delegate to self
        //- this is important, otherwise the method under (4) won't be called and your button will remain disabled!
        pc.delegate = self;
        //- disable the button to prevent creating another popover
        [_btnSettings setEnabled:NO];
    }

4. Implement the following method in the UIPopoverControllerDelegate protocol,
    - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
    {
        //- renable the setting button
        [_btnSettings setEnabled:YES];
    }
As the name suggests, this method gets call whenever the user click outsdie the popover view.

0 Comments

Making the Popover View Modal

2/3/2012

0 Comments

 
By default, popover view is dismissed when the user clicks anywhere outside of the view. Depending on your context, this may or may not be a desirable UI behavior.
You can make the popover view modal. Doing so prevents the user from clicking outside the popover view to dismiss the view. Of course, under this approach, you need to provide a mechanism to dismiss the popover.

The following assumes that we have a view (whose class is viewController) where a 'button' is located, and on clicking this button a popover view appears. This popoverview's class is popoverViewController.
1. Inside @implementation of the popover viewcontroller class file,
    - (void)viewDidAppear:(BOOL)animated
    {
        self.modalInPopover = YES;
    }
Note: self.modalInPopover must be in viewDidAppear. It won't work in viewDidLoad. Setting this property to 'YES' makes the view modal.

2. Create a protocol
Inside the popover view controller .h file, before @interface,
    @protocol PopoverViewControllerDelegate;
Under @interface, create a property,
    @property (nonatomic, weak) id<PopoverViewControllerDelegate>delegate;
After @end,
    @protocol PopoverViewControllerDelegate <NSObject>
    - (void)PopoverViewController:(PopoverViewController *)controller didClick:(BOOL)clicked;
    @end
Next, synthesize the delegate. Inside the controller .m file, after @implementation,
    @synthesize delegate;

3. You need to create a button that the user can click once they are finished doing whatever they need to do inside the popover view. This can be a button that triggers further actions such as saving some information that the user has entered or a 'cancel' button. But you need to provide a button as this allows you to link it to the mechanism that dismisses the popover.
Assuming that it is a 'Done' button, you could have a method like this in the popover view controller class file:
    - (IBAction)btnDone:(id)sender {
            [[self delegate] PopoverViewController:self
                                      didClick:YES];
    }

4. You need to obtain a reference to the popover segue so that you can dismiss the popover.
Under @interface of viewController.h,
    @property (strong, nonatomic) UIStoryboardPopoverSegue* popSegue;
Synthesize this property in viewController.m,
    @synthesize popSegue = _popSegue;
Inside (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender,
    if ([segue.identifier isEqualToString:@NAME_OF_YOUR_SEGUE]) {
        self.popSegue = (UIStoryboardPopoverSegue *)segue;
    }

5. Finally, you need to implement the protocol inside the viewController class.
Import the header for PopoverViewController,
    #import "PopoverViewController.h"
Make this class confirms to the PopoverViewControllerDelegate protocol, by adding <PopoverViewControllerDelegate> after @interface, such that it looks something like:
    @interface ViewController: UIViewController <PopoverViewControllerDelegate>
Add the protocol method insider @implementation
    - (void)PopoverViewController:(PopoverViewController *)controller didClicked:(BOOL )clicked
    {
        if ([self.popSegue.popoverController isPopoverVisible])
        {
            [self.popSegue.popoverController dismissPopoverAnimated:YES];
        }
    }
0 Comments

    Archives

    August 2013
    July 2013
    June 2013
    May 2013
    January 2013
    October 2012
    September 2012
    March 2012
    February 2012

    Categories

    All
    Apple Policy
    In App Purchase
    Ios Programming
    Our Apps

    RSS Feed

    Disclaimers

    Here are some resources that I find useful in writing iOS apps. These are not necessarily unique as they are based on various sources online.
    This is mainly to provide a source of reference to myself and my associates but if it can be of use to someone else, that is good.
    Note that information is provided here as is. Use at your own risk. There is no guarantee that it is accurate. We will update the information as time and resources permit.

    Powered by Create your own unique website with customizable templates.