Resize Mkannotationview Image When Map Zooms in and Out

Resize MKAnnotationView Image When map zooms in and out?

Actually on the default MKMapView- the annotation (e.g. pin or image) and the callout (e.g. bubble) remain the same size as you zoom in or out. They do not scale. But I get your point- in relation to the map they appear to be growing as the map zooms out and shrinking as the map zooms in.

So there are two solutions to your problem and they work slightly differently:

  1. Implement -(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated from the MKMapViewDelegate Protocol Reference - which you've already done.
  2. Attach a UIPinchGestureRecognizer to the MKMapView object and then implement the action.

Option #1 - mapView:regionDidChangeAnimated: will be called for either a scroll or a zoom event - basically any time the map region changed as the name implies. This results in a slightly less smooth resizing of icons, because the map events are fired less frequently.

My preferences is for Option #2 - Attach a UIPinchGestureRecognizer to the MKMapView object and then implement the action. Pinch gesture events are fired rather quickly, so you get a smooth resizing of the icon. And they only fire for a recognized pinch event- so they won't fire during a scroll event.

The action methods invoked must conform to one of the following signatures:

- (void)handleGesture;
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;

You have to be careful to not override the maps default zoom behavior. See this post: "UIMapView: UIPinchGestureRecognizer not called" for more info. Short answer is that you have to implement shouldRecognizeSimultaneouslyWithGestureRecognizer: and return YES.

All told here is some sample code:

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];

self.mapView.mapType = MKMapTypeStandard; // also MKMapTypeSatellite or MKMapTypeHybrid

// Add a pinch gesture recognizer
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
pinchRecognizer.delegate = self;
[self.mapView addGestureRecognizer:pinchRecognizer];
[pinchRecognizer release];
}

#pragma mark -
#pragma mark UIPinchGestureRecognizer

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinchRecognizer {
if (pinchRecognizer.state != UIGestureRecognizerStateChanged) {
return;
}

MKMapView *aMapView = (MKMapView *)pinchRecognizer.view;

for (id <MKAnnotation>annotation in aMapView.annotations) {
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return;

// handle our custom annotations
//
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// try to retrieve an existing pin view first
MKAnnotationView *pinView = [aMapView viewForAnnotation:annotation];
//Format the pin view
[self formatAnnotationView:pinView forMapView:aMapView];
}
}
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}

So at this point- you again have several options for how to resize the annotation. Both of the following code samples rely on Troy Brant's code for getting the zoom level of an MKMapView.

  1. Resize BOTH the annotation image and the callout using a transform. Personally I think the transform results in a cleaner looking resize. But in most cases- resizing the callout is not called for.
  2. Resize just the annotation image - I use Trevor Harmon's Resize a UIImage the right way but again my opinion is that it's not as clean looking a resize.

Here is some more sample code:

- (void)formatAnnotationView:(MKAnnotationView *)pinView forMapView:(MKMapView *)aMapView {
if (pinView)
{
double zoomLevel = [aMapView zoomLevel];
double scale = -1 * sqrt((double)(1 - pow((zoomLevel/20.0), 2.0))) + 1.1; // This is a circular scale function where at zoom level 0 scale is 0.1 and at zoom level 20 scale is 1.1

// Option #1
pinView.transform = CGAffineTransformMakeScale(scale, scale);

// Option #2
UIImage *pinImage = [UIImage imageNamed:@"YOUR_IMAGE_NAME_HERE"];
pinView.image = [pinImage resizedImage:CGSizeMake(pinImage.size.width * scale, pinImage.size.height * scale) interpolationQuality:kCGInterpolationHigh];
}
}

If this works, don't forget to mark it as the answer.

Resizing Custom MKAnnotationView According to MapKit Zoom Level

Since you are using iOS 4.0 I would suggest using a class that conforms to the MKOverlay protocol instead of MKAnnotationView. Overlays zoom with the map and will scale appropriately. You can probably use 1 overlay to handle all your annotations. Check out the HazardMap demo Apple provided in the 2010 WWDC talks on http://developer.apple.com

Alternatively, you could use something like the k nearest neighbors algorithm to group annotations per zoom scale. However, that can be kind of slow if you have a lot of annotations. I tried it once with several thousand annotations and did not like the performance hit that was incurred. I think < 1000 annotations might have decent performance with this method though.

How to resize MKAnnotationView on iOS6?

Apple suggests resizing the .image property of an annotation view. In my case shown below, I looked at the UIImage that was set in the viewforAnnotation and re-scaled it to the zoom level in a UIPinchGestureRecognizer

   UIImage *orangeImage = [UIImage imageNamed:@"Orange210.PNG"];
CGRect resizeRect;
//rescale image based on zoom level
resizeRect.size.height = orangeImage.size.height * scale;
resizeRect.size.width = orangeImage.size.width * scale ;
NSLog(@"height = %f, width = %f, zoomLevel = %f", resizeRect.size.height, resizeRect.size.width,zoomLevel );
resizeRect.origin = (CGPoint){0,0};
UIGraphicsBeginImageContext(resizeRect.size);
[orangeImage drawInRect:resizeRect];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
pinView.image = resizedImage;

Don't resize annotation on MKMapView zoom-in/out

If you want to create shapes that are fixed to geography, you may want to look at overlays instead of annotations.

iOS7AnimatedMapOverlay shows how to add overlays to annotations.

MKAnnontation pin image resize issue

Though I cannot reproduce the issue, but recommend couple of changes:

  1. separate the view configuration logic, lets subclass MKAnnotationView, like so:

    class CarAnnotationView: MKAnnotationView {
    override var annotation: MKAnnotation? {
    didSet {
    let size = CGSize(width: 38, height: 44)
    UIGraphicsBeginImageContext(size)
    UIImage(named: "carIcon")?.draw(in: CGRect(origin: .zero, size: size))
    self.image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    }
    }
    }
  2. change within mapView(_:viewFor:) to take advantage of the reusable view, like so:

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
    userPinView = mapView.dequeueReusableAnnotationView(withIdentifier: "carId") as? CarAnnotationView
    if (userPinView == nil) {
    userPinView = CarAnnotationView(annotation: nil, reuseIdentifier: "carId")
    }

    userPinView.annotation = annotation
    userPinView.setNeedsLayout()
    // userPinView.centerOffset = CGPoint(x: 0, y: -view.bounds.midY)

    return userPinView
    }

    guard annotation is MKPointAnnotation else { return nil }

    let annotationIdentifier = "AnnotationIdentifier"
    ...
    return annotationView

    }
  3. delete unnecessary variable

    var pin = MKAnnotationView()


Related Topics



Leave a reply



Submit