Reputation: 1859
I'd like to a-synchronically load images for my custom MKAnnotationView; I'm already using the EGOImageView-framework (it goes very well with UITableViews), but I fail to make it work on MKMapView. Images seem to be loaded, but I cannot refresh them on the map - [myMap setNeedsDisplay]
does nothing.
Upvotes: 29
Views: 34430
Reputation: 402
Thank you @Vladimir for the help! Your answer inspired my answer. I made some changes to make it clearer.
func addAnnotation(coordinate: CLLocationCoordinate2D) {
let annotation = Annotation()
annotation.coordinate = coordinate
annotations.append(annotation)
mapView.addAnnotation(annotation)
for index in 0..<annotations.count {
if let view = mapView.view(for: annotations[index]) as? AnnotationView {
if index == 0 {
view.imageView.image = NSImage(named: "icon_positioning")
} else {
view.imageView.image = NSImage(named: "icon_positioning")
}
}
}
}
Also the protocol in MKMapview needs to implement:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let view = mapView.dequeueReusable(withClass: AnnotationView.self, annotation: annotation)
if index == 0 {
view.imageView.image = NSImage(named: "icon_positioning")
} else {
view.imageView.image = NSImage(named: "icon_positioning")
}
return view
}
By the way, the AnnotationView initialization here is:
public extension MKMapView {
func dequeueReusable<T: MKAnnotationView>(withClass name: T.Type,annotation: MKAnnotation?) -> T {
if let view = dequeueReusableAnnotationView(withIdentifier: T.identifier()) as? T {
return view
}
let view = T.init(annotation: annotation, reuseIdentifier: T.identifier())
return view
}
}
Thanks again @Vladimir for the answer
Upvotes: 0
Reputation: 489
I wanted to refresh user location pin with new selected avatar. I found another fast solution for that case. I have 2 screens. The first one is for selecting avatar and the second is for displaying user on map.
swift 5 You can change user location image by creating MKAnnotationView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
let userIdentifier = "UserLocation"
var userView = mapView.dequeueReusableAnnotationView(withIdentifier: userIdentifier)
if userView == nil {
userView = MKAnnotationView(annotation: annotation, reuseIdentifier: userIdentifier)
} else {
userView?.annotation = annotation
}
userView!.image = UIImage(named: "avatar1") //your image
return userView
}
return nil
}
So if user will change avatar to something else, for example to "avatar2" it won't refresh.
In order to refresh user location image i added this code in viewWillAppear()
self.mapView.showsUserLocation = false
self.mapView.showsUserLocation = true
Upvotes: -1
Reputation: 1177
(I don't see how to indicate that this post pertains to zerodiv's answer.) I was able to get zerodiv's method to work by adding a kickstart of sorts, forcing a meaningless but different coordinate, then restoring the prior, correct one. The screen doesn't flash at all because of the first location.
CLLocationCoordinate2D center = mapView.centerCoordinate;
CLLocationCoordinate2D forceChg;
forceChg.latitude = 0;
forceChg.longitude = curLongNum;
mapView.centerCoordinate = forceChg;
mapView.centerCoordinate = center;
Upvotes: -1
Reputation: 5257
This worked for me
#import "EGOImageView.h"
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
//ENTER_METHOD;
if([annotation isKindOfClass:[MKUserLocation class]]) return nil;
MKPinAnnotationView *annView;
static NSString *reuseIdentifier = @"reusedAnnView";
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5.0f, 0.0f);
annView.opaque = NO;
annView.image = [[UIImage imageNamed:@"tempImage.png"] retain];
YourModel *p = annotation; // make this conform to <MKAnnotation>
EGOImageView *egoIV = [[EGOImageView alloc] initWithPlaceholderImage:[UIImage imageNamed:@"tempImage.png"]];
[egoIV setDelegate:self];
egoIV.imageURL = [NSURL URLWithString:p.theUrlToDownloadFrom];
[annView addSubview:egoIV];
[egoIV release];
return [annView autorelease];
}
Upvotes: 1
Reputation: 6062
I found only one reliable way to update annotation, others methods didn't work for me: just removing and adding annotation again:
id <MKAnnotation> annotation;
// ...
[mapView removeAnnotation:annotation];
[mapView addAnnotation:annotation];
This code will make -[mapView:viewForAnnotation:] to be called again and so your annotation view will be created again (or maybe reused if you use dequeueReusableAnnotationViewWithIdentifier) with correct data.
Upvotes: 13
Reputation: 290
This is the only way I've found to force redraw of MKAnnotationViews:
// force update of map view (otherwise annotation views won't redraw)
CLLocationCoordinate2D center = mapView.centerCoordinate;
mapView.centerCoordinate = center;
Seems useless, but it works.
Upvotes: 1
Reputation: 170849
I haven't tried it myself, but it might work:
Get a view for annotation using MKMapView - (MKAnnotationView *)viewForAnnotation:(id <MKAnnotation>)annotation
method and set new image to it.
Edit: Tried to do that myself and this approach worked fine for me:
// Function where you got new image and want to set it to annotation view
for (MyAnnotationType* myAnnot in myAnnotationContainer){
MKAnnotationView* aView = [mapView viewForAnnotation: myAnnot];
aView.image = [UIImage imageNamed:@"myJustDownloadedImage.png"];
}
After calling this method all annotations images were updated.
Upvotes: 37