I am trying to rotate an image that is added to MKMapView as an annotation.
This is the code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation
{
if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
{
//return default view if annotation is NOT of type IGAMapAnnotation...
return nil;
}
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"IGAMapAnnotation"];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"IGAMapAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
// THIS IS IT!
if ([myLocation.type isEqual: #"PLANE"]) {
UIImage *planeImage = [UIImage imageNamed:#"planetracked.png"];
UIImageView *planeImageView = [[UIImageView alloc]initWithImage:planeImage];
planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);
annotationView.image = planeImageView;
}
return annotationView;
}
It obviously gives me an error as annotationView.image should assign an image and not UIImageView. I have tried various methods rotating just an image, for example this:
- (UIImage *)rotateImage:(UIImage *)image onDegrees:(NSString *)heading {
double angle = [heading doubleValue];
CGSize s = {image.size.width, image.size.height};
UIGraphicsBeginImageContext(s);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0,image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextRotateCTM(ctx, 2*M_PI*angle/360);
CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width, image.size.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
They do not work either -- no image appears on the map.
Anyone knows how to rotate an annotation image on MKMapView?
Million thanks!
Instead of:
annotationView.image = planeImageView;
which is definitely wrong (the image property is a UIImage while planeImageView is a UIImageView), use addSubview: to add the UIImageView to the annotation view (leaving the view's image property nil and unused).
However, you'll also need to make some other adjustments so that:
The image is centered exactly on the coordinate (instead of its corner), and
Tapping anywhere on the image brings up the callout (instead of only one specific corner)
To do these things, increase the frame sizes of both views to account for the maximum width possible from a rotation (which is the square root of 2 times the original width assuming image is a square) and set the image view's contentMode to "center" so the image is not distorted by these frame size changes.
The other big issue is that if you have IGAMapAnnotations whose type is not "PLANE", they will either be:
Invisible if a new annotation view is created (because image is not set nor is any subview added to the annotation view), or,
Showing a "plane" image with the heading of some other annotation because the annotation view was dequeued (and is being re-used for another annotation).
To avoid the two types of annotations ("plane"/"not plane") from re-using each other's views, I suggest using a different re-use identifier for each type (not each annotation) and apply type-specific changes to the view.
The revised viewForAnnotation method would look like this:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
{
//return default view if annotation is NOT of type IGAMapAnnotation...
return nil;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *)annotation;
BOOL typeIsPlane = [myLocation.type isEqualToString:#"PLANE"];
int planeImageViewTag = 42;
NSString *reuseId = typeIsPlane ? #"IGAMapAnnotationPlane" : #"IGAMapAnnotationOther";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if (typeIsPlane)
{
//Here, just add the image view to the annotation view with no
//rotation. Only want to add the image view to the annotation
//view ONCE when the annotation view is initially created. If
//view is dequeued, it will already have an image view and we
//just update its rotation.
UIImage *planeImage = [UIImage imageNamed:#"planetracked.png"];
UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
planeImageView.tag = planeImageViewTag;
planeImageView.contentMode = UIViewContentModeCenter;
[annotationView addSubview: planeImageView];
CGRect avFrame = annotationView.frame;
//"1.5" on next line is the square root of 2 rounded up a bit.
avFrame.size = CGSizeMake(planeImage.size.width*1.5,
planeImage.size.height*1.5);
annotationView.frame = avFrame;
planeImageView.frame = annotationView.frame;
}
else
{
//If this IGAMapAnnotation is not a "plane",
//show some other default image.
//(Or, you could return nil to show a default red pin.)
annotationView.image = [UIImage imageNamed:#"NotAPlane.png"];
//May or may not need to set centerOffset.
//Either remove or adjust 0,0 as needed to
//center the image on the coordinates.
annotationView.centerOffset = CGPointMake(0, 0);
}
}
else
{
annotationView.annotation = annotation;
}
//At this point, we have a new or dequeued annotation view ready
//and pointing to the current annotation.
//Now make any annotation-specific changes to the view...
if (typeIsPlane)
{
UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);
//Replace M_PI_2 with rotation specific to this annotation's heading.
}
return annotationView;
}
By the way, use isEqualToString: instead of isEqual: with NSStrings.
For the removeAnnotations: problem, it must be that mapLocations contains new instances of the annotations on the map. To remove existing annotations, you have to provide a reference to the exact same objects that were added originally.
If you are always removing all annotations and re-adding all annotations, you can just do [self.mapView removeAnnotations:self.mapView.annotations];.
If you are only removing some annotations, you'll need to keep references to the ones originally added or iterate through the map view's annotations array and identify which ones should be deleted (keep a temporary NSMutableArray as the list of "annotations to remove") and then call removeAnnotations: with that list of annotations to remove.
The following seems to work. Million thanks to Anna without whom it would not have!
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if (! [annotation isKindOfClass:[IGAMapAnnotation class]]) {
return nil;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
BOOL typeIsPlane = [myLocation.navaidType isEqualToString:#"PLANE"];
BOOL typeIsOne = [myLocation.navaidType isEqualToString:#"ONE"];
BOOL typeIsTwo = [myLocation.navaidType isEqualToString:#"TWO"];
BOOL typeIsThree = [myLocation.navaidType isEqualToString:#"THREE"];
int planeImageViewTag = 42;
NSString *reuseId;
if (typeIsPlane)
reuseId = #"IGAMapAnnotationPlane";
else if (typeIsOne)
reuseId = #"IGAMapAnnotationOne";
else if (typeIsTwo)
reuseId = #"IGAMapAnnotationTwo";
else if (typeIsThree)
reuseId = #"IGAMapAnnotationThree";
else
reuseId = #"IGAMapAnnotationOther";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if (typeIsPlane)
{
UIImage *planeImage = [UIImage imageNamed:#"mapPLANE.png"];
UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
planeImageView.tag = planeImageViewTag;
planeImageView.contentMode = UIViewContentModeCenter;
[annotationView addSubview: planeImageView];
CGRect avFrame = annotationView.frame;
//"1.5" on next line is the square root of 2 rounded up a bit.
avFrame.size = CGSizeMake(planeImage.size.width*1.5,
planeImage.size.height*1.5);
annotationView.frame = avFrame;
planeImageView.frame = annotationView.frame;
}
else if (typeIsOne)
{
annotationView.image = [UIImage imageNamed:#"one.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else if (typeIsTwo)
{
annotationView.image = [UIImage imageNamed:#"two.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else if (typeIsThree)
{
annotationView.image = [UIImage imageNamed:#"three.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else
return nil;
}
else
{
annotationView.annotation = annotation;
}
if (typeIsPlane)
{
// Convert current heading string to double
double headingDouble = [currentHeading doubleValue];
UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
planeImageView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(headingDouble));
}
return annotationView;
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am clearly not getting this. I'm trying to work out how to rotate a custom image of map annotations. i.e. multiple icons pointing different directions. I have loop'ed over a whole bunch of airplane data and I want to simply show the direction the plane is heading.
Review the code that I have managed to piece together to get at least half of it working and provide a suggestive idea on how to turn the image based on a variable.
Abstract View of the loop'ed data
NSMutableArray *locations = [[NSMutableArray alloc]init];
CLLocationCoordinate2D location;
MKPointAnnotation *myAnn;
myAnn = [[MKPointAnnotation alloc]init];
location.latitude = nLatitudeFloat;
location.longitude = nLongitudeFloat;
myAnn.coordinate = location;
myAnn.title = nRealname;
//Add the Annotation object to the list so when the map is presented all points are listed on the map.
[locations addObject:myAnn];
//[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
[self.mapView addAnnotations:locations];
Update of the annotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]]) return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"airplane21.png"] ;
pinView.calloutOffset = CGPointMake(0, 32);
pinView.transform = CGAffineTransformMakeRotation(30); <------AT THE MOMENT I HAVE JUST HARD CODED THIS TO SEE IF IT WORKS. IT ROTATES THE ENTIRE ANNOTATION
// Add a detail disclosure button to the callout.
//UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//pinView.rightCalloutAccessoryView = rightButton;
// Add an image to the left callout.
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"airplane21.png"]];
pinView.leftCalloutAccessoryView = iconView;
iconView.transform = CGAffineTransformMakeRotation(30);
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Any ideas?
I have seen this by the way. I just wasn't confident to know if it would be suitable or not.
Rotate annotation image on MKMapView
I had the same problem and I have a solution that seems to work.
You need to first make a custom annotation that can hold the data that you want (ex. coordinates, your plane heading). When you loop through your data make sure you're using that custom annotation. For example
CustomAnnotation* annotation = [[CustomAnnotation alloc] init];
annotation.coordinates = ...
annotation.bearing = ...
Then in your viewForAnnotation method, you can get that info by doing something like
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
CustomAnnotation* myAnn = (CustomAnnotation*)annotation;
double bearing = myAnn.bearing; // or whatever it's called
...
}
Hope this helped.
Edit: For rotating your image, I found the following code snippet somewhere. It works but it pixellates your image a little bit.
#interface UIImage (RotationMethods)
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
#end
#implementation UIImage (RotationMethods)
static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
//UIGraphicsBeginImageContext(rotatedSize); // For iOS < 4.0
UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, 0.0);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
// Rotate the image context
CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#end
Stick that in your .m, and on any UIImage you can now do [someUIImage imageRotatedByDegrees:yourDegrees];
So now in your viewForAnnotation method you can do something like
UIImage* image = [[UIImage imageNamed:#"yourImage.png"] imageRotatedByDegrees:degrees];
annView.image = image;
I have several MKPolygons for which I am using rendererForOverlay method override. Now inside each such polygons I need my annotation view to display.
I observe that the annotation view positions are quite inaccurate. Only when I zoom fully to the MKPolygon do I see the annotation view centered inside that MKPolygon.
I tried setting center of the MKAnnotationView derived class instance, but to no avail.
I tried playing with centerOffset property but to no avail. I am not sure what values I could pass to it to make the whole thing centered inside MKPolygon.
I am using my own MKAnnotationView derived subclass, not built in iOS MKPinAnnotationView or such.. Here is my viewforAnnotation implementation:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
//show default blue dot for user location...
return nil;
}
static NSString *reuseId = #"MapAnnotationID";
MWAnnotationView *av = (MWAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (av == nil)
{
av = [[MWAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
av.canShowCallout = NO;
//note that this my custom UIView derived class to show UI.
MWMapAnnotationView * mapAnnView = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotationView" owner:nil options:nil] firstObject];
mapAnnView.tag = TAG_ANNOTATION;
[av addSubview:mapAnnView];
av.centerOffset = CGPointMake(0, -15);
}
else
{
av.annotation = annotation;
}
if (map.region.span.longitudeDelta > MAX_LONGITUDEDELTA / 4)
{
av.hidden = YES;
}
else
{
av.hidden = NO;
}
//custom UI elements of my subview
mapAnnView.labelCapital.text = capital;
mapAnnView.labelPopulation.text = population;
if (imageName)
{
mapAnnView.imageAnnotation.image = [UIImage imageNamed:imageName];
}
else
{
mapAnnView.imageAnnotation.image = nil;
}
return av;
}
UPDATE:
It turns out setting centerOffset has no effect. Tried setting it at different points inside viewForAnnotation but to no avail. For anyone who is wondering, I have my own MKAnnotationView subclass where I have overridden centerOffset setter. Tested with iOS simulator version 8.0.
I add custom annotation in a mapview. Based on the internal model of the app the annotations can change color and title (although position may not change). I am using dequeueReusableAnnotationViewWithIdentifierin the method
- (MKAnnotationView *)mapView:(MKMapView *) viewForAnnotation:(id <MKAnnotation>)
The strange thing is that when the model changes the annotations are "refreshed" to use the correct title and color (I just use removeAnnotations: and add the new ones), but later when playing with the map some old annotations with wrong color are dequeued. I use a different identifier each time the model changes.
here is the code:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation{
// in case it's the user location, we already have an annotation, so just return nil
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
if ([annotation isKindOfClass:[APGSAnnotation class]]){
APGSAnnotation *gsn = (APGSAnnotation*) annotation;
NSString *GSAnnotationIdentifier = [NSString stringWithFormat:#"gid_%lu_%#", (unsigned long)gsn.gs.gID, self.car.energyType];
MKAnnotationView *markerView = [theMapView dequeueReusableAnnotationViewWithIdentifier:GSAnnotationIdentifier];
if (markerView == nil) {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:GSAnnotationIdentifier];
annotationView.canShowCallout = YES;
annotationView.image = [self customizeAnnotationImage:gsn.gs];
annotationView.opaque = NO;
UIImageView *sfIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:gsn.logo]];
annotationView.leftCalloutAccessoryView = sfIconView;
// http://stackoverflow.com/questions/8165262/mkannotation-image-offset-with-custom-pin-image
annotationView.centerOffset = CGPointMake(0,-annotationView.image.size.height/2);
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = rightButton;
return annotationView;
}else{
markerView.annotation = annotation;
return markerView;
}
}
return nil;
}
and the customize method
- (UIImage*)customizeAnnotationImage:(APGS*)gs{
UIImage *markerImage;
if (gs.gID == self.best.gID) {
markerImage = [UIImage imageNamed:#"marker_red.png"];
}else if (gs.type == k1){
markerImage = [UIImage imageNamed:#"marker_blue.png"];
}else if (gs.type == k2){
markerImage = [UIImage imageNamed:#"marker_green.png"];
}else if (gs.type == k3){
markerImage = [UIImage imageNamed:#"marker_purple.png"];
}else if (gs.type == k4){
markerImage = [UIImage imageNamed:#"marker_brown.png"];
}
UIImage *logoImage = [UIImage imageNamed:gs.logo];
// size the flag down to the appropriate size
CGRect resizeRect;
resizeRect.size = markerImage.size;
CGSize maxSize = CGRectInset(self.view.bounds, kAnnotationPadding, kAnnotationPadding).size;
maxSize.height -= self.navigationController.navigationBar.frame.size.height + kCallOutHeight;
if (resizeRect.size.width > maxSize.width)
resizeRect.size = CGSizeMake(maxSize.width, resizeRect.size.height / resizeRect.size.width * maxSize.width);
if (resizeRect.size.height > maxSize.height)
resizeRect.size = CGSizeMake(resizeRect.size.width / resizeRect.size.height * maxSize.height, maxSize.height);
resizeRect.origin = CGPointMake(0.0, 0.0);
float initialWidth = resizeRect.size.width;
UIGraphicsBeginImageContextWithOptions(resizeRect.size, NO, 0.0f);
[markerImage drawInRect:resizeRect];
resizeRect.size.width = resizeRect.size.width/2;
resizeRect.size.height = resizeRect.size.height/2;
resizeRect.origin.x = resizeRect.origin.x + (initialWidth - resizeRect.size.width)/2;
resizeRect.origin.y = resizeRect.origin.y + kLogoHeightPadding;
[logoImage drawInRect:resizeRect];
// Create string drawing context
UIFont *font = [UIFont fontWithName:#"DBLCDTempBlack" size:11.2];
NSString * num = [NSString stringWithFormat:#"%4.3f",[gs getL]];
NSDictionary *textAttributes = #{NSFontAttributeName: font,
NSForegroundColorAttributeName: [UIColor whiteColor]};
CGSize textSize = [num sizeWithAttributes:textAttributes];
NSStringDrawingContext *drawingContext = [[NSStringDrawingContext alloc] init];
//adjust center
if (resizeRect.size.width - textSize.width > 0) {
resizeRect.origin.x += (resizeRect.size.width - textSize.width)/2;
}else{
resizeRect.origin.x -= (resizeRect.size.width - textSize.width)/2;
}
resizeRect.origin.y -= kTextPadding;
[num drawWithRect:resizeRect
options:NSStringDrawingUsesLineFragmentOrigin
attributes:textAttributes
context:drawingContext];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
Based on car type the annotations should change color.
Based on the title, the answer is NO :)
Normally you would dequeue the view and reset all relevant properties of the view
workaround:
What you can consider is: if the views would change too much, you could switch to a different reusingIdentifier, thereby switching the queue and 'circumventing' the cached views
I have a map on which I want to display both custom annotations with images and one default looking annotation with a red pin.
I've made my view into a map delegate in order to load the custom images, but what happens is that the default looking pin I want is not showing (since I don't load an image for it).
I'm adding a shortened version of my code below (with remarks).
How can I load an image for this pin? Is there a standard way to access the pin UIImage, or should I make the annotation somehow?
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *SFAnnotationIdentifier = #"SFAnnotationIdentifier";
MKPinAnnotationView *pinView =
(MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
MKPointAnnotation* pointAnnotation = (MKPointAnnotation*)annotation;
if (!pinView)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:SFAnnotationIdentifier];
for (id location in self.locations) {
// if this is a "special" point loaded
if () {
UIImage *image = ; // get custom image from somewhere
annotationView.image = image;
return annotationView;
}
}
// if the code made here, I want the pin to be regular
return annotationView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
OK, solved it.
return nil;
does the trick and gives the default view.
Change
UIImage *image = ; // get custom image from somewhere
to
UIImage *image = [UIImage imageNamed:#"YourPin.png"]; // get custom image from somewhere
And maybe you need to change the offset of annotationView
annotationView.centerOffset = CGPointMake( 0, annotationView.centerOffset.y - annotationView.image.size.height/2 );
The annotationView bubble size is too small 9 out of 10 times.
I call [self.mapView selectAnnotation:self.selectedVenue animated:YES]; to show annotation view when select a row. Whether I set animated: YES or NO it still displays wrong size. However, if I increase size of map view height to at lease 200 pixels, everything looks fine except for the map view is too big for 3.5" screen.
I want the map view to be this size and annotation bubble to cover the title and subtitle correctly.
image: https://dl.dropboxusercontent.com/u/5105730/anno.png
Here's how I create my annotation view.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
if ([annotation isKindOfClass:[FSVenue class]]) {
static NSString *PlaceAnnotationIdentifier = #"Place Identifier";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:PlaceAnnotationIdentifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:PlaceAnnotationIdentifier];
}
annotationView.annotation = annotation;
UIButton *calloutButton = [UIButton buttonWithType:(UIButtonTypeContactAdd)];
calloutButton.tintColor = self.themeColor;
annotationView.enabled = YES;
annotationView.pinColor = MKPinAnnotationColorGreen;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = calloutButton;
annotationView.animatesDrop = YES;
return annotationView;
}
return nil;
}
You have to zoom the visible rect of your mapview after adding your annotations like this.
[self.yourMapview addAnnotations:self.yourAnnotationsArray];
[self zoomToAnnotations];
Call this method after adding your annotation like this
-(void)zoomToAnnotations{
MKMapRect zoomRect = MKMapRectNull;
for (_yourAnnotation in self.yourMapView.annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(_yourAnnotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
if (MKMapRectIsNull(zoomRect)) {
zoomRect = pointRect;
}else{
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
}
if (zoomRect.size.width == 0.10) /* for single annotation available in map */
{
zoomRect = MKMapRectMake(zoomRect.origin.x, zoomRect.origin.y, 100000, 100000);
}
[[self yourMapView] setVisibleMapRect:zoomRect edgePadding:UIEdgeInsetsMake(50, 50, 50, 50) animated:YES];
}