Hi, I am interested in zoom in/out card in Maps.app for iPhone, how it made? The symbols output by nm command shows what they used only LKKeyframeAnimation … this is enough? Maybe you have an idea how it made in Maps.app or how to do it from scratch?
Unfortunately with the SDK still under NDA we can’t really discuss iPhone stuff. However to build an app like that on the Mac with CA would be possible using the CATiledLayer and the animations (key frame being one of them). There is a sample app in the code for the book that illustrates the titled layer and several examples of using the various animation types.
it’s exactly what I need. :)
Could you elaborate on using CATiledLayer with multiple tile sets, in other words, it looks like the sample app just has a high resolution tiles, and if zoomed out you could have say a lower resolution two tile representation of the same image. Now when zoomed out you don’t need to access the high res files only the smaller low res.
This is the same standard used by google maps, etc…
I did something similar to the above by subclassing CALayer and creating a TileManagerLayer, TileSetLayer and a TileLayer class.
The tile manager has a tile set for each zoom level, 0,1,2… 0=2 tiles, 1=8 tiles 2=32 tiles The tile set manages which tiles are visible and cached, tile is really just a CALayer
I am wondering if I couldn’t simplify this using CATiledLayer, however I have read that even the google maps app on the iphone does not use that CATiledLayer as it has some limitations.
The bottom line is this is a GIS mapping app, latitude etc, and we have to draw based on latitude longitude, which is very tricky, especially when you zoom between layers as the frame changes.
There must be an easier way and I would love to hear what your approach would be?
Yes it should be easier :)
So if you took my example code and made a second set of images (say by down sampling the image in photoshop to be 1/4th it size and then retiling) you could then use the zoom level from the current context to determine which set of image tiles you should use.
I will try to blog that as its too late to put it into the book for this printing (woot the paper copy is on its way :)
Thanks again for taking the time to post!
Thanks for the reply,
Here is the current layer stack for our custom tile engine (iPhone). View is a UIView subclass and Layer is a CALayer subclass. The MapLayer switches between the tileset layers when zooming and also maintains a size equal to the visible tileset, it also adjusts the vector layer size and redraws the vector layer when necessary. The visible tileset decides which tilelayers to load and draw based on the mapView bounds.
MapView MapLayer VectorDrawingLayer TileSetLayer0 [TileLayer0..1] TileSetLayer1 [TileLayer0..8] TileSetLayer2 [TileLayer0..32]
Am I insane for doing it this way, possibly but, since the bounds of the tile sets and vector layers always remain the full size of the world in this case, it’s very easy to get accurate latitude and longitude as opposed to our first approach where the bounds constantly changed and drawing was a nightmare.
Although this was painful to create, it does offer complete control, and is working pretty well at this point. For example, tileLayers can be pre loaded if it appears the user is about to pan off the screen. When switching tileSets one can fade out while the other fades in. Lat, Lon math is dirt simple. There are still a couple of zoom issues using 3d transform, but I am hoping the CAAnimation book will help to solve these. It’s also wicked fast.
I would love to hear your thoughts on this approach, even if you completely disagree?
I would also love to hear how you believe the iPhone google maps app works?
How would you do it?
No need to post code just pseudo thoughts.
Hi, I tried to use CATiledLayer for GIS project and had a problem with implementation of the method “drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx”. When zooming in, the method “CGContextGetClipBoundingBox” returns us bounds, the size of which is divided by two at each zoom level (for example, we start with tileSize = 64, after several zooming steps we get bounds size equal to 2). Because of that, i can’t implement map with zoom level equal to 20 (like google maps). What did i miss ?
Its complex, try taking a look at the example that comes with my Core Animation book. It does something similar to what you are asking about.
Thanks for the fast reply,
I have another question. How can i subclass CALayer to make method “drawLayer:InContext” work in another thread, like CATiledLayer do ?
The answer to that is not simple or quick.
I’d start with doing something like pushing an NSOperation onto an operation queue for each treaded draw you want with the delegate and the information you need to draw the stuff required.
Before I headed down the path of trying to make CALayer multi-threaded I would work extra extra hard to try to make things work with something that is built in. Something like CATiledLayer.
I’m trying to implement my own native maps control using the iPhone SDK and need some advice on picking the best set of API’s for the job. All maps services including Yahoo Maps, Google Maps, and Virtual Earth send data in tiles (each being 256x256 pixels). I already have all of the geometry for this worked out. I’m also able to successfully form a HTTP tile request and actually get a PNG that contains the exact tile(s) I’m looking for.
Now I need some advice on how to actually present the tiles to the user.
Quartz would definitely be too inefficient, especially since I’d be redrawing an area of 320x460 pixels every time the user moved their finger on the screen. I’m sure this would also consume a fair amount of iPhone’s CPU, so this is definitely not the direction I want to go.
Then I found CATiledLayer, which at first looked perfect, but after doing some research, I learned that some people didn’t have a lot of luck using this method. One person said that CATiledLayer goes crazy when using high zoom levels. Is this true? Did anyone have any success implementing maps using CATiledLayer? Also, if I were to use CATiledLayer, I’d probably use a UIScrollView along with it. How efficient is UIScrollView in hosting large views? A maps view with a zoom level of 16 would have to be around 67 million pixels in area.
After reading about CATiledLayer’s issues, I was thinking I could implement my own ‘Tile Manager’ in Core Animation. How would I go about doing this? Of course I would still be dealing with a UIScrollView that holds a content view with insanely huge sizes.
Finally, I was thinking I could use OpenGL to layout the tiles. Basically I would create a simple 320x460 OpenGL ES view and then in it, I would manually draw the tiles as textures, implement scrolling, zooming (using transformations so I don’t have to deal with a UIScrollView), and so on. Did anyone use this approach? I would probably use NSOperationQueue to load the tiles and then redraw the view (which should be done by the GPU).
Thanks for your help,
I have not tried CATiledLayer with a zoom level of 16 so I’m not sure what trouble it would cause.
Creating your own CATiledLayer is fraught with peril, well perhaps not peril, but at least hassle. There is a ton of code there that will likely be difficult to reproduce. Basically the tiled layer creates a cache of all your drawing and reuses it when possible, asking you for more as needed.
The OpenGL ES solution is essentially what CATiledLayer is supposed to be doing for you but you might be able to get around whatever issues there are there by doing it yourself.
Good luck! Please let us know which direction you end up going.
Thank you for your response. I decided to use OpenGL for rendering. I’ve never really learned OpenGL but after playing around with it for around 2 days, I really ‘got it’. I’m also impressed with the performance - right now, I get a constant 40-50fps when panning around my custom Tile view.
For now, I’m just trying to build the foundation for my Maps view by implementing a simple Tile view. So far I got panning working without any problems. I’m still trying to figure out how I’m going to implement scaling. I’ll probably end up using glScalef and then ask for new tiles once the view receives the touchesEnded event. Since glScalef multiplies the matrix, should I also multiply variables like the current render offset in my code (see the sample below)?
Here is what I have so far: http://idisk.mac.com/matt.rajca-Public?view=web Note that the default zoom level on the Tile view is 2 for testing purposes.
I’d just like to follow up on my attempts with this project. OpenGL ended up being a pain, especially when trying to add animation efficiently. I ended up going with CATiledLayer and currently haven’t experienced any problems. I think others were experiencing problems because they were hosting extremely large views in a UIScrollView. In my project, simply created a 320x460 UIView and whenever the user pans around, I simply change the position of the CATiledLayer that is hosted inside it.
Your book really helped me understand these concepts very well so thank you very much!
Now I’m just facing one issue, zooming in using double tapping works (I simply double the scale), however when trying to zoom in using a multi-touch “pinch”, I keep getting weird results. I’ve been facing this problem for the past couple of days so I was hoping you could help me. I’m probably missing something obvious in my touchesMoved: handler. I’ve looked at your iPhone CATiledLayer example but still no luck.
If you have some time, I’d appreciate it if you could take a look at my code.
Matt matt.rajca (at) me (dot) com
First thanks to Bill for the great book, and pointing us all in the right direction.
I’m afraid that I have the same problem as Matt with the touch events.
In my case, I based it off of Bill’s tiling iPhone demo (though I changed it to use a png instead), but finger-dragging causes it to jump and pinch-zooming doesn’t work at all. It’s been driving me crazy trying to figure it out.
Matt, your code example link isn’t up anymore. I was curious to look at it.
Hi, I am also trying to do a native kinda application in Iphone. I am only using UIScrollView and have almost done it but without that much perfection. With the help of a 5*5 matrix of UIImageViews and adjusting the contentOffSet I have done it. All the images are being loaded from a server.
The problem is after double tap or pinch zoom, only after loading all the new images the contentView appears. So it appears like after I try the zoom, i have to wait for 5-6 seconds(looking at the map that i tried to zoom) for the zoomed map(with a new set of 25images) to come and that too will appear all of a sudden. Then I heard of CATiledLayer. I think if I use tiles instead of imageViews, then after I apply zoom it will only appear like the normal zooming - The background map being slowly replaced by the tiles rather than appearing all of a sudden. It will give the feel of the zooming thing also.
Since I havent worked or tried CATiledLayer till no, I thought to get a look at the link posted above. But when I downloaded and tried it, it doesnt seem like the Iphone code. So can somebody help me with CATiledLayer