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:
- Implement
-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated
from the MKMapViewDelegate Protocol Reference - which you've already done. - 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.
- 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.
- 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:
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()
}
}
}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
}delete unnecessary variable
var pin = MKAnnotationView()
Related Topics
Uicollectionview Horizontal Paging Not Centered
Swapping Child Views in a Container View
Implementing Unit Testing with iOS
Uitextview Content Size Different in iOS7
Uicollectionview Select and Deselect Issue
How to Get Current Longitude and Latitude Using Cllocationmanager-Swift
Uicollectionview Sticky Header in Swift
iOS Swift Mapkit Custom Annotation
How to Get Selected Value from Uipickerview
How to Debug "Invalid Bundle" Error Which Happens Only After Submitting to App Store
How to Hide/Show Tabbar When Tapped Using Swift in iOS8
iOS 11 Uitableview Delete Rows Animation Bug
How to Get Indexpath in Prepareforsegue
Change the Uitextview Text Direction
How to Find Indexpath for Tapped Button in Tableview Using Seque