Drawables and Touchables

Drawables and Touchables are two faces of the same medal: a way to draw something onto the pdf page and interact with it. An object implementing the MFOverlayDrawable protocol needs to define a -(void)drawInContext:(CGContextRef)ctx method, while the MFOverlayTouchable protocol define a -(BOOL)containsPoint:(CGPoint)point method. The drawInContext method is used to draw the drawable over the page, while the containsPoint method is used to check for user interaction. Since touchables and drawables are defined in page space coordinates, both methods should take this into account: if we want to draw an opaque red square in the bottom left of the page, the drawInContext method could look like this

    -(void)drawInContext:(CGContextRef)ctx {
        ...
        CGContextSetRGBFillColor(ctx, 1.0, 0.0, 0.0, 1.0);
        CGContextFillRect(ctx, CGRectMake(0,0,100,100));
        ...
    }

while, if we want to make the touchable active in the same area of the above red square, we should fill the containsPoint method with something like this

    -(BOOL)containsPoint:(CGPoint) point {

        return CGRectContainsPoint(touchableRect,point);

    }

where the touchableRect is elsewhere defined with CGRectMake(0,0,100,100).

To provide the MFDocumentViewController with drawable and touchable you just need to implement the MFDocumentOverlayDataSource in some object, and add it to the MFDocumentViewController with the addOverlayDataSource method (you can remove it with the removeOverlayDataSource method). When a page is drawn, each overlay data source is asked to provide an array of drawables and touchables for the page through the invocation of the following methods

    -(NSArray *)documentViewController:(MFDocumentViewController *)dvc drawablesForPage:(NSUInteger)page;

    -(NSArray *)documentViewController:(MFDocumentViewController *)dvc touchablesForPage:(NSUInteger)page;

It is a good idea to have touchable and drawables ready to be returned at any time, so don't do slow things like parsing xml files to generate them as needed. Overlay data sources will also be notified when an user tap a touchable through the invocation of -(void)documentViewController:(MFDocumentViewController *)dvc didReceiveTapOnTouchable:(id<MFOverlayTouchable>)touchable. Each overlay data source should check if the touchable is one of its own and handle the event accordingly

    @interface MyTouchable : NSObject <MFOverlayTouchable> {

        CGRect touchableRect;
    }

    @property (nonatomic,readwrite) CGRect touchableRect;

    @end

    -(void)documentViewController:(MFDocumentViewController *)dvc didReceiveTapOnTouchable:(id<MFOverlayTouchable)touchable {

        if([touchables containsObject:touchable]) { // A set of touchables associated to this overlay data source.

            MyTouchable * myTouchable = (MyTouchable *)touchable;

            NSLog(@"Touched touchable at rect %@",NSStringFromRect(myTouchable.touchableRect));

        }
    }

As bottom line, you can also have an object that implements both the MFOverlayDrawable and MFOverlayTouchable protocol, so if you want to draw something and make it interactive too, you just have to create a single class.