菜鸟教程小白 发表于 2022-12-12 16:25:09

ios - 自定义注释在更新时不会在 map View 上更新


                                            <p><p>我正在执行 <code>willChangeValueForKey</code> 和 <code>didChangeValueForKey</code> 调用,但即使使用它们,mapView 委托(delegate)也永远不会通过 <code>mapView: viewForAnnotation:</code> 来更新事情。如何强制更新 <code>MKAnnotation</code>?</p>

<p><code>annotationView.image</code> 不会在图像更改时更新,<code>annotationView.image</code> 也不会更新。据我的 NSLog 行所知,当 <code>MKAnnotation</code> 更新时,<code>mapView: viewForAnnotation:</code> 不会再次被调用。</p>

<p><strong>.h</strong></p>

<pre><code>#import &lt;UIKit/UIKit.h&gt;
#import &lt;Foundation/Foundation.h&gt;
#import &lt;MapKit/MapKit.h&gt;

@interface MapAnnotation : NSObject &lt;MKAnnotation&gt;

@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) initWithCoordinate:(CLLocationCoordinate2D) c;
- (CLLocationCoordinate2D) getCoordinate;
- (void) addPlace:(MapAnnotation*) place;
- (int) placesCount;
- (void) cleanPlaces;
- (UIImage *) getPin;
@end
</code></pre>

<p><strong>.m</strong></p>

<pre><code>#import &#34;MapAnnotation.h&#34;

@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 ( == 1) {
      return self.currentSubTitle;
    }
    else{
      return @&#34;&#34;;
    }
}


- (NSString*) title {
    if ( == 1) {
      return self.currentTitle;
    }
    else{
      return ];
    }
}


- (void)addPlace:(MapAnnotation *)place {
    ;
    ;
    ;
    ;
    ;
}


- (CLLocationCoordinate2D)getCoordinate {
    return self.coordinate;
}


- (void)cleanPlaces {
    ;
    ;
    ;
    ;
    ;
    ;
}


- (id)initWithCoordinate:(CLLocationCoordinate2D) c {
    self.coordinate=c;
    self.places=[ initWithCapacity:0];
    return self;
}


- (int)placesCount {
    return ;
}


- (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);
    [ setStroke];
    [ setFill];
    CGContextFillEllipseInRect(ctx, circleRect);
    CGContextStrokeEllipseInRect(ctx, circleRect);

    // Dot Content
    [ setStroke];
    [ 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 = ;
    if ( != 1) {
      NSString *label = ];
      CGSize stringSize = ;
      [label drawAtPoint:CGPointMake(size.width / 2 - stringSize.width / 2, size.height / 2 - stringSize.height / 2)
            withAttributes:@{NSFontAttributeName:font}];
    } else {
      NSString *label = ;
      CGSize stringSize = ;
      [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
</code></pre>

<p><strong>ma​​pView:viewForAnnotation:</strong></p>

<pre><code>- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &lt;MKAnnotation&gt;)annotation {
    MKAnnotationView *annotationView = ;
    if(!annotationView) {
      annotationView = [ initWithAnnotation:annotation reuseIdentifier:@&#34;MyAnnoation&#34;];
      annotationView.rightCalloutAccessoryView = ;
    }

    annotationView.enabled = YES;
    if ([(MapAnnotation*)annotation placesCount] == 1) {
      annotationView.canShowCallout = YES;
    }
    annotationView.image = [(MapAnnotation*)annotation getPin];
    NSLog(@&#34;%@&#34;, );

    return annotationView;
}
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>正如评论中提到的,除了 <code>title</code> 和 <code>subtitle</code> 之外,注释属性的更改不会自动导致 View 更新。</p>

<p>更改 <code>title</code> 和 <code>subtitle</code> 将在显示时自动更新标注,只要更改导致 KVO 通知(例如,如果使用带有 <code>ann.title = xxx</code> 或通过手动发出 KVO 通知,因为您有自定义 getter)。</p>

<p>要自动更新图像,您可能需要使用自定义注释 View 来观察底层注释属性的变化并自行刷新(在 <code>init</code> 中调用 <code>addObserver</code> ,在<code>observeValueForKeyPath</code>更新图片,在<code>dealloc</code>调用<code>removeObserver</code>)。您也可以使用非 KVO 方法,例如自定义通知或委托(delegate)(但仍使用自定义注释 View )来实现。</p>

<p>使用现有代码,在不创建自定义注释 View 和使用KVO等的情况下,快速手动更新注释 View 的方法是在注释更新后立即获取注释的当前 View 并更新<code>图像</code> 属性。只要 <code>viewForAnnotation</code> 中的代码与设置 <code>image</code> 的逻辑相同,这应该可以工作。</p>

<p>我假设在应用程序的某个地方(有时<em>在</em>注释已经添加),它通过调用<code>addPlace</code>来更新注释中的位置。之后,您可以尝试以下操作:</p>

<pre><code>;

//obtain the current view of someExistingAnnotation...
MKAnnotationView *av = ;

//update its image property to force refresh...
av.image = ;
//also set canShowCallout (it might have been NO)
</code></pre>

<p><br/>
不相关但当前的 <code>viewForAnnotation</code> 不能正确处理可能的 View 重用和/或除您的自定义注释之外的注释类型(例如会导致当前代码崩溃的用户位置蓝点)。我建议将其更改为:</p>

<pre><code>- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &lt;MKAnnotation&gt;)annotation {
    if (! ])
    {
      //annotation is NOT a &#34;MapAnnotation&#34;, return nil for default view...
      return nil;
    }

    MKAnnotationView *annotationView = ;
    if(!annotationView) {
      annotationView = [ initWithAnnotation:annotation reuseIdentifier:@&#34;MyAnnoation&#34;];
      annotationView.rightCalloutAccessoryView = ;
    }

    //update view&#39;s annotation to current in case it&#39;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(@&#34;%@&#34;, );

    return annotationView;
}
</code></pre></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 自定义注释在更新时不会在 mapView 上更新,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/20026321/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/20026321/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 自定义注释在更新时不会在 map View 上更新