Thursday 30 September 2010

MonoTouch... CATiledLayer example (like DeepZoom/multi-scale-image)

UPDATE 2-Oct-02: Thanks to Miguel's assistance the NPhotoScroller code on github is now working!

The CORRECT port of this Objective-C snippet...

+ (Class)layerClass {
  return [CATiledLayer class];
} this c# (requires using MonoTouch.ObjCRuntime;)

[Export ("layerClass")]
public static Class LayerClass () {
  return new Class (typeof (CATiledLayer));

and not the dodgy hack I came up with below...

Original Post:
Normally code posted on this blog actually works (or close to it...) but today I have a half-done port of an Objective-C sample that I just can't seem to finish off :-(

The idea was to port Apple's PhotoScroller sample, which demonstrates how to use the CATiledLayer, to MonoTouch.

The work-in-progress is on github: NPhotoScroller*... however it isn't quite finished and I'm hoping someone will point out what is missing.

If you download the sample (and grab the images from Apple), the my MonoTouch port looks like this:

It seems to be working, since the image is being successfully drawn using tiles BUT there are too many tiles for this zoom level. It should look like the image below (ie. 4 tiles) but I can only get that effect by hardcoding TilingView.cs::line 96 to a specific zoom level of 0.125

Using a different hardcoded zoom level of 0.25 results in this output, so the tiles are 'definitely kinda working'...

The problem? Zooming is totally broken - any attempt to pinch/zoom on these images breaks. TilingView.cs::line 95 ALWAYS returns a scale of 1 - it never changes. ImageScrollView.cs::line 157 this.ZoomScale = this.MinimumZoomScale seems to have no effect: no matter what the MinimumZoomScale is (eg. 0.08), ZoomScale is always 1 and the context.GetCTM() CGAffineTransform never reflects a change in zoom level.

If you switch from 'tiled' to 'whole' images (PhotoViewController.cs::line 63 useTiledImage = false;) then zooming works perfectly (if greedily from a memory perspective). I would love to hear any suggestions!!

Aside: I did have one minor issue with the port... what to do with this code in TilingView.m

+ (Class)layerClass {
return [CATiledLayer class];

It's been ported as the following in TilingView.cs but I could be way off base...

private CATiledLayer __layer;
public override CALayer Layer {get
{ // set in ctor
return __layer;


* NOTE: If you download the sample from github, you MUST also download Apple's original sample to get their test image files.


  1. [Export("layerClass")]
    public static Class layerClass() {
    return new Class("CATiledLayer");

    /// initWithImageName
    public TilingView (string name, SizeF size) : base(new RectangleF(0, 0, size.Width, size.Height))
    imageName = name;

    var tiledLayer = (CATiledLayer)this.Layer;
    tiledLayer.LevelsOfDetail = 4;

  2. Hehe yeah - but I love that about the MonoTouch community.

    Thanks for your help, though. I have big plans for CATiledLayer, now that I've got it working. Hopefully the sample is useful for someone else too.



Note: only a member of this blog may post a comment.