0
votes

I'm currently rotating the image property of an MKAnnotationView using CGAffineTransformMakeRotation. However, the whole view in this case gets rotated, as well as the callout bubble. So I followed the suggestion within MKAnnotationView Only Rotate the Image property, and am now creating a UIImageView and adding it as a subview to MKAnnotationView. The image displays and rotates now without issue. However, now the MKAnnotationView doesn't respond to a touch event. I need it to behave just as it did before - on tap/touch it should show the callout bubble. Any ideas what I need to do?

Initial way I tried (which rotates callout bubble):

MKAnnotationView *aView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
aView.image = [UIImage imageNamed:@"mapPin.png"];
float newRad = degreesToRadians(degreesToRotate);
[aView setTransform:CGAffineTransformRotate(CGAffineTransformIdentity, newRad)];

Using a UIImageView and adding as a subview:

MKAnnotationView *aView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
UIImageView *iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"mapPin.png"]];
iv.userInteractionEnabled = YES;
[aView addSubview:iv];
aView.canShowCallout = YES;

Update I tried to add a gesture recognizer, though it doesn't work. imageTapped method doesn't get called when I tap on the UIImageView within the MKAnnotationView on the map. This is within the method: - (MKAnnotationView *)mapView:(MKMapView *)mView viewForAnnotation:(id )annotation

MKAnnotationView *aView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];

UIImageView *iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"mapPin.png"]];
iv.userInteractionEnabled = YES;
iv.exclusiveTouch = NO;

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
[iv addGestureRecognizer:tapGesture];

[aView addSubview:iv];
5

5 Answers

2
votes

I tried all the answers here and none of them completely worked, but I found a different solution that did!

I believe the easiest way to do this is to rotate the UIImage itself before setting the image property of the MKAnnotationView. If you have hundreds and hundreds of annotations this may perform poorly, but if you just need to rotate a couple things (like in my case), it works just fine.

I found a helper class to rotate UIImages, and then simply used that to rotate the UIImage before setting the image property of MKAnnotationView.

Helper class is here: http://www.catamount.com/forums/viewtopic.php?f=21&t=967

Now, to rotate the UIImage property of the MKAnnotationView on the map without sacrificing the callout bubble, do the following:

- (MKAnnotationView *)mapView:(MKMapView *)pMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MyAnnotationView *annotationView = [[MyAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"WayPoint"]; 

    annotationView.image = [annotationView.image imageRotatedByDegrees:45.0];

    annotationView.canShowCallout = YES;

    return annotationView;
}
2
votes

I realize this is now a very old question, but I recently encountered this problem and it had a very simple solution. The only reason the annotation view becomes unclickable when using an image view is that the MKAnnotationView has a size of (0,0) when no image is set. The image view is visible because the annotation view doesn't clip to bounds. All I had to do was set the frame on the annotation view to make it clickable again.

MKAnnotationView *aView = [[MKAnnotationView alloc] initWithAnnotation:annotation  reuseIdentifier:@"Pin"];
UIImageView *iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"mapPin.png"]];
[aView addSubview:iv];
annotationView.frame = (CGRect) {
            .origin = CGPointZero,
            .size = iv.frame.size
        };
aView.canShowCallout = YES;
0
votes

Try doing something like this to the image view to see if you can pass its touch event to the annotation.

//Do this before you add the imageview as a subview
self.imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
[self.imageView addGestureRecognizer:tapGesture];



- (void) imageTapped:(UITapGestureRecognizer *)tapGesture {
    MKAnnotationView * annotationView =  (MKAnnotationView *)tapGesture.view.superview;
    if (annotationView.selected) {
        [annotationView setSelected:NO animated:YES];
    } else {
        [annotationView setSelected:YES animated:YES];
    }
}
0
votes

You can use the following Swift extension method to help. The most popular answer results in a blurry image using the linked helper library.

extension UIImage {

    func rotated(degrees degrees : Int) -> UIImage {
        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRectMake(0,0,self.size.width, self.size.height))
        let rotation = CGFloat(degrees) * CGFloat(M_PI) / 180
        let t = CGAffineTransformMakeRotation(rotation);
        rotatedViewBox.transform = t;
        let rotatedSize = rotatedViewBox.frame.size;
        UIGraphicsBeginImageContextWithOptions(rotatedSize, false, 0.0);
        let context = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(context, rotatedSize.width/2, rotatedSize.height/2);
        CGContextRotateCTM(context, rotation);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextDrawImage(context, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), self.CGImage);
        let rotatedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return rotatedImage;
    }
}

Usage:

annotationView.image = UIImage(named: "my_image")!.rotated(degrees: 45)
-2
votes

// Just set the image property before adding the subview and it works like charm

MKAnnotationView *aView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
UIImageView *iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"mapPin.png"]];

aView.image = [UIImage imageNamed:@"mapPin.png"];   //   just this line

[aView addSubview:iv];
aView.canShowCallout = YES;