我正在执行 willChangeValueForKey
和 didChangeValueForKey
调用,但即使使用它们,mapView 委托(delegate)也永远不会通过 mapView: viewForAnnotation:
来更新事情。如何强制更新 MKAnnotation
?
annotationView.image
不会在图像更改时更新,annotationView.image
也不会更新。据我的 NSLog 行所知,当 MKAnnotation
更新时,mapView: viewForAnnotation:
不会再次被调用。
.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MapAnnotation : NSObject <MKAnnotation>
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString *currentTitle;
@property (nonatomic, retain) NSString *currentSubTitle;
@property (nonatomic, retain) NSString *category;
@property (nonatomic, retain) NSString *pin;
- (NSString*) title;
- (NSString*) subtitle;
- (id) initWithCoordinateCLLocationCoordinate2D) c;
- (CLLocationCoordinate2D) getCoordinate;
- (void) addPlaceMapAnnotation*) place;
- (int) placesCount;
- (void) cleanPlaces;
- (UIImage *) getPin;
@end
.m
#import "MapAnnotation.h"
@interface MapAnnotation()
@property (strong) NSMutableArray *places;
@end
@implementation MapAnnotation
@synthesize coordinate = _coordinate;
@synthesize currentTitle = _currentTitle;
@synthesize currentSubTitle = _currentSubTitle;
@synthesize places = _places;
@synthesize category = _category;
@synthesize pin = _pin;
- (NSString*) subtitle {
if ([self placesCount] == 1) {
return self.currentSubTitle;
}
else{
return @"";
}
}
- (NSString*) title {
if ([self placesCount] == 1) {
return self.currentTitle;
}
else{
return [NSString stringWithFormat"%d places", [self placesCount]];
}
}
- (void)addPlaceMapAnnotation *)place {
[self willChangeValueForKey"title"];
[self willChangeValueForKey"subtitle"];
[self.places addObject:place];
[self didChangeValueForKey"title"];
[self didChangeValueForKey"subtitle"];
}
- (CLLocationCoordinate2D)getCoordinate {
return self.coordinate;
}
- (void)cleanPlaces {
[self willChangeValueForKey"title"];
[self willChangeValueForKey"subtitle"];
[self.places removeAllObjects];
[self.places addObject:self];
[self didChangeValueForKey"title"];
[self didChangeValueForKey"subtitle"];
}
- (id)initWithCoordinateCLLocationCoordinate2D) c {
self.coordinate=c;
self.places=[[NSMutableArray alloc] initWithCapacity:0];
return self;
}
- (int)placesCount {
return [self.places count];
}
- (UIImage *)getPin {
// begin a graphics context of sufficient size
CGSize size = CGSizeMake(26, 26);
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
// get the context for CoreGraphics
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect imageRect = CGRectMake(0, 0, size.width, size.height);
// Draw Dot
CGRect circleRect = CGRectInset(imageRect, 4, 4);
[[UIColor blackColor] setStroke];
[[UIColor yellowColor] setFill];
CGContextFillEllipseInRect(ctx, circleRect);
CGContextStrokeEllipseInRect(ctx, circleRect);
// Dot Content
[[UIColor blackColor] setStroke];
[[UIColor blackColor] setFill];
CGAffineTransform transform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(ctx, transform);
CGContextSetLineWidth(ctx, 2.0);
CGContextSetCharacterSpacing(ctx, 1.7);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
UIFont *font = [UIFont fontWithName"Arial" size:11.0];
if ([self placesCount] != 1) {
NSString *label = [NSString stringWithFormat:@"%d", [self placesCount]];
CGSize stringSize = [label sizeWithAttributes:@{NSFontAttributeName:font}];
[label drawAtPoint:CGPointMake(size.width / 2 - stringSize.width / 2, size.height / 2 - stringSize.height / 2)
withAttributes:@{NSFontAttributeName:font}];
} else {
NSString *label = [NSString stringWithFormat:@"%@", self.pin];
CGSize stringSize = [label sizeWithAttributes:@{NSFontAttributeName:font}];
[label drawAtPoint:CGPointMake(size.width / 2 - stringSize.width / 2, size.height / 2 - stringSize.height / 2)
withAttributes:@{NSFontAttributeName:font}];
}
// make image out of bitmap context
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
// free the context
UIGraphicsEndImageContext();
return retImage;
}
@end
mapView:viewForAnnotation:
- (MKAnnotationView *)mapViewMKMapView *)mapView viewForAnnotationid <MKAnnotation>)annotation {
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:@"MyAnnoation"];
if(!annotationView) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MyAnnoation"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
annotationView.enabled = YES;
if ([(MapAnnotation*)annotation placesCount] == 1) {
annotationView.canShowCallout = YES;
}
annotationView.image = [(MapAnnotation*)annotation getPin];
NSLog(@"%@", [annotation title]);
return annotationView;
}
正如评论中提到的,除了 title
和 subtitle
之外,注释属性的更改不会自动导致 View 更新。
更改 title
和 subtitle
将在显示时自动更新标注,只要更改导致 KVO 通知(例如,如果使用带有 ann.title = xxx
或通过手动发出 KVO 通知,因为您有自定义 getter)。
要自动更新图像,您可能需要使用自定义注释 View 来观察底层注释属性的变化并自行刷新(在 init
中调用 addObserver
,在observeValueForKeyPath
更新图片,在dealloc
调用removeObserver
)。您也可以使用非 KVO 方法,例如自定义通知或委托(delegate)(但仍使用自定义注释 View )来实现。
使用现有代码,在不创建自定义注释 View 和使用KVO等的情况下,快速手动更新注释 View 的方法是在注释更新后立即获取注释的当前 View 并更新图像
属性。只要 viewForAnnotation
中的代码与设置 image
的逻辑相同,这应该可以工作。
我假设在应用程序的某个地方(有时在注释已经添加),它通过调用addPlace
来更新注释中的位置。之后,您可以尝试以下操作:
[someExistingAnnotation addPlace:anotherPlace];
//obtain the current view of someExistingAnnotation...
MKAnnotationView *av = [mapView viewForAnnotation:someExistingAnnotation];
//update its image property to force refresh...
av.image = [someExistingAnnotation getPin];
//also set canShowCallout (it might have been NO)
不相关但当前的 viewForAnnotation
不能正确处理可能的 View 重用和/或除您的自定义注释之外的注释类型(例如会导致当前代码崩溃的用户位置蓝点)。我建议将其更改为:
- (MKAnnotationView *)mapViewMKMapView *)mapView viewForAnnotationid <MKAnnotation>)annotation {
if (! [annotation isKindOfClass:[MapAnnotation class]])
{
//annotation is NOT a "MapAnnotation", return nil for default view...
return nil;
}
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:@"MyAnnoation"];
if(!annotationView) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MyAnnoation"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
//update view's annotation to current in case it's being re-used
annotationView.annotation = annotation;
annotationView.enabled = YES;
if ([(MapAnnotation*)annotation placesCount] == 1) {
annotationView.canShowCallout = YES;
}
else {
annotationView.canShowCallout = NO;
}
annotationView.image = [(MapAnnotation*)annotation getPin];
NSLog(@"%@", [annotation title]);
return annotationView;
}
关于ios - 自定义注释在更新时不会在 map View 上更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20026321/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |