I have an MKMapView that I am considering rotating in order to more conveniently display a series of Annotations to my users.
As of now I am planning on simply rotating the entire view with a CGAffineTransform, but I wanted to know if anyone had any experience with MKMapView rotation.
Are there any pitfalls or "gotchas" that you came across when adding rotation?
Is there an easier way to rotate a mapview?
If I have an overlay will the convertCoordinate:toPointToView: method still work the same way? I would assume that I'd have to apply the same transform to my overlay for the points to line up, but maybe the method is smarter than that.
If there's anything that you think could help out I'd love to hear it all.
Edit: After much experimentation I believe that I'll be using static maps that I can rotate and overlay myself, however, I would still be interested in any information about MKMapView rotation.
I also plan to use rotated MKMapView in my application. To show annotations unrotated I use the following code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
...
annotationView.transform = GAffineTransformInvert(mapView.transform);
...
}
It seems to work for me.
Sorry to revive a finished topic, but one more 'gotcha': if you size your map view to be large enough to rotate so that it always covers the entire screen then you'll end up cropping the 'Google' logo from the bottom left. This is explicitly contrary to the licence under which you use MapKit and may be grounds for an app rejection. In practice, adding a static version of the Google logo as a UIImageView on top seems to be considered acceptable by all parties.
That's a fresh sample of MKMapView rotation with iPhone ccelerometer. Hope it'll help.
I started working with MKMapView rotations and have found that:
When you apply a CGAffineTransform to the map view the method convertCoordinate:toPointToView: works the same.
Annotations rotate with the view, including annotation text.
Region that fits still appears to fit to a region on the screen, it doesn't fit to the map view (I made my map view larger than its parent view so it could rotate without showing the view behind).
Related
I have a UIScrollView that contains a custom UIView. In my UIView I am overriding drawRect to draw a path using CGContextStrokePath. I would like to slightly alter the way the zoom works. Pinch zooming out will show more of the paths on the screen. This is what I want but i want the line width to stay the same not shrink as you zoom out so that they are still clear to the user.
I thought I would just do this (myUIView zoom target is called _lineView)
-(void)scrollViewDidZoom:(UIScrollView *)pScrollView
{
_lineView.zoomScale = _scrollView.zoomScale;
[_lineView setNeedsDisplay];
}
and then just calculate an appropriate line stroke size in my _lineView drawRect method to give the effect of constant line width as you zoom out.
This is really slow and I have read that this is expected as drawrect is not optimised to be called many times a second.
I then started looking at using a GLKView instead and just rendering the whole thing in opengl directly. The problem with this is I will have to implement all of the zooming and panning myself (with all the lovely zoom and pan bounce effects you get for free in UiScrollView). I will also have to implement all the controls I want to use in opengl, buttons etc.
Is there a way to do this whilst still using Quartz2d? I feel like opengl will give me lots of power but it will take me much longer to get the rest of my app done if I go down that route.
I figured this out. I found a simple way to do this that does not slow down the zoom / bouncing animations at all and is very fast and fluid.
Quartz has a class called CAShapeLayer that lets you do some pretty cool stuff. Among these is being able to set a CGPath property and specify a linewidth. Changes are reflected in the view.
So i basically call shapeLayer.lineWidth from my scrollViewDidZoom method and it does exactly what i need.
What I would do if I were you is to use default zooming behavior while zooming (which does not redraw, but instead just applies a transform to the zoomed view, which can be done by the GPU very, very quickly, but as you have noticed can lead to inferior quality).
Then, when the user finished zooming, redraw the whole view as you do now. The appropriate delegate method is scrollViewDidEndZooming:withView:atScale:.
This way, you have fast (but slightly ugly) zooming, and nice (but slightly, probably unnoticeably, slower) display after the zoom is finished.
I am creating a graphing calculator application in OpenGL on iOS, and I would like to implement pinch zooming that works like the google maps application or uiscrollview zooming. I'm pretty sure I can't use a uiscrollview because the content of the graph is being generated dynamically.
Implementing zooming where the center of the screen is assumed to be the center of the zoom is easy, but in other cases it is not obvious to me how its being implemented. Can anyone point me in the right direction?
The view that does your custom drawing should be capable of drawing at a certain scale. When your user zooms in or out of the scroll view, send the appropriate zoom factor and let the view redraw itself. The changing bounds is not a problem. The scroll view adjusts its bounds as you pan inside, so its subviews shouldn't have any concern over the bounds of the scroll view.
Of course, you'll probably have to consider performance. For example, it may be too slow to redraw the graph at every frame as a user zooms. Instead, you may only want to redraw when the user stops zooming, which is what Maps.app does.
There are many other considerations for this problem, but that would be where I would start.
EDIT: Ah, I overlooked the OpenGL aspect. Still, with a GL layer-backed view, you still should be able to make the appropriate translations based on both the current zoom factor as well as the scroll view's bounds.
I need to transform-rotate a MKMapview based on the course of the CLLocations I get from CoreLocation.
I basically have this already:
mapview.transform = CGAffineTransformMakeRotation(degreesToRadians(course));
However, this is not good since this rotates the entire map, with annotations. Now I can fix the annotations, but the problem is it also rotates the Google logo!
After searching all other posts here on this problem the main answer was this is not possible with the google logo but the thing is, I have seen some Apps (Trapster for example) that actually do this, they rotate the map but the google logo is always in the same place.
So my question is, is there a new function I don't know about that purely rotates the content of the map, or do all these apps rotate the mapview, fix rotations of the annotations and perhaps add their own google image to the view containing the mapview?
Thanks!
Probably you could do by finding the right view with mapView.subviews.
If I do:
for (UIView *aView in mapView.subviews){
NSLog(#"view class: %#", aView.class);
}
I get back:
view class: UILabel
view class: UIView
view class: UIImageView
view class: UILabel
I would guess one of these is the google logo and the map itself...
When i click on a pin on the map and if the pin is on the borders of the iPhone screen, the bubble comes off the screen, i.e. Half ourside of the viewport and half inside the viewport.
Is there is any property etc which will show the bubble automatically centered on the screen.!
Check this image below to know more about what i mean
http://i.stack.imgur.com/ZSWmZ.png
Any help will be highly appreciated.
You can try to make it so that everytime an annotation is selected, you change the map's center coordinate to the coordinate of your annotation? Instead of calculating the pop up view's dimensions, just do it every time instead. Here's the code to do this. Put this into your delegate for MKMapView
- (void)mapView:(MKMapView *) theMapView didSelectAnnotationView:(MKAnnotationView *)annoView{
[theMapView setCenterCoordinate:annoView.annotation.coordinate animated:YES];
}
Once you've done this, you should be all set.
Also, it's curious to note, that when I tried implementing a mapview, and I added annotations, whenever I selected them, the map automatically moved so as to display the whole calloutView. I wonder why yours isn't doing that. Anyway, if my answer helped, please accept it as your answer. Thnx
Mapkit does a great job of positioning the map when annotations are selected but it can't magically account for other UI elements you've placed in the scene that are obscuring things.
You need to either resize your mapview when your search box is down so it is not obscuring it or you need to add logic to reposition the map if a annotation is selected which is near the top of the view when the search box is visible.
there are already some questions on this topic. Unfortunately none of them helped me in anyway. So here is the thing. I am working on an app atm and it has one tabcontroller with two tabs, which contain multiple navigationcontroller on top of each other. Now in one tab at the top level navigation controller, I want to draw some graphics in landscape orientation.
Unfortunately using the shouldAutorotateToInterfaceOrientation method returning YES does not help in anyway.
Now I was wondering whether I could just hide the statusBar and the navigationBar and then draw my graphics so that it looks like it is landscape orientation. But then I also would like to add some labels. I am quite sure I also could turn those around 90 degrees. But this is probably not the right approach here. And I want to submit my app someday...
So now I was hoping someone knows whats the best approach here and how to realize it.
Thanks.
I found a solution somewhere else. The idea is to use the CGAffineTransform method. It allows you to transform the complete coordinate system of a uiview. The piece of code underneath rotatets it to landscape. Now when you draw, the drawing relates to the rotated coordinate systems and everything is drawn in landscape orientation.
CGAffineTransform transform=CGAffineTransformIdentity;
transform=CGAffineTransformRotate(transform, (90.0f*22.0f)/(180.0f*7.0f));
transform=CGAffineTransformTranslate(transform, 80, 80);
This does what I want. But anyway, if there are any other suggestions, please post them!