刷新 MKMapView 上的 MKAnnotationView

发布于 2024-08-10 07:42:42 字数 176 浏览 7 评论 0原文

我想为我的自定义 MKAnnotationView 同步加载图像;我已经在使用 EGOImageView 框架(它与 UITableViews 配合得很好),但我无法让它在 MKMapView 上工作。图像似乎已加载,但我无法在地图上刷新它们 - [myMap setNeedsDisplay] 不执行任何操作。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

北城半夏 2024-08-17 07:42:42

我自己没有尝试过,但它可能会起作用:

使用 MKMapView - (MKAnnotationView *)viewForAnnotation:(id)annotation 方法获取注释视图,并为其设置新图像。

编辑:我自己尝试这样做,这种方法对我来说效果很好:

//  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"];
}

调用此方法后,所有注释图像都已更新。

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.

作妖 2024-08-17 07:42:42

我发现只有一种可靠的方法来更新注释,其他方法对我不起作用:只需再次删除并添加注释:

id <MKAnnotation> annotation;

// ...

[mapView removeAnnotation:annotation];
[mapView addAnnotation:annotation];

此代码将使 -[mapView:viewForAnnotation:] 再次被调用,因此您的注释视图将被再次创建(或者如果您使用 dequeueReusableAnnotationViewWithIdentifier,则可能会重用)和正确的数据。

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.

挽梦忆笙歌 2024-08-17 07:42:42

这是我发现强制重绘 MKAnnotationViews 的唯一方法:

// 强制更新地图视图(否则注释视图不会重绘)

CLLocationCooperative2D center = mapView.centerCooperative;

mapView.centerCoordinate = 中心;

看似无用,但确实有效。

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.

笑脸一如从前 2024-08-17 07:42:42

这对我有用

#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];
}

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];
}
难理解 2024-08-17 07:42:42

谢谢@Vladimir 的帮助!你的回答启发了我的回答。
我做了一些更改以使其更清晰。

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")
            }
        }
    }
}

另外,MKMapview 中的协议需要实现:

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
}

顺便说一下,这里的 AnnotationView 初始化是:

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
    }
}

再次感谢@Vladimir 的回答

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

后知后觉 2024-08-17 07:42:42

(我不知道如何表明这篇文章与 Zerodiv 的答案有关。)我能够通过添加某种启动,强制一个无意义但不同的坐标,然后恢复先前的正确坐标来使 Zerodiv 的方法发挥作用。由于第一个位置,屏幕根本不闪烁。

CLLocationCoordinate2D center = mapView.centerCoordinate; 
CLLocationCoordinate2D forceChg;
forceChg.latitude = 0;
forceChg.longitude = curLongNum;

mapView.centerCoordinate = forceChg;
mapView.centerCoordinate = center;

(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;
善良天后 2024-08-17 07:42:42

我想用新选择的头像刷新用户位置图钉。我为这种情况找到了另一个快速解决方案。我有 2 个屏幕。第一个用于选择头像,第二个用于在地图上显示用户。

迅捷5
您可以通过创建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
 }

因此如果用户将头像更改为其他内容,例如“avatar2”,它将不会刷新。

为了刷新用户位置图像,我在 viewWillAppear() 中添加了此代码

 self.mapView.showsUserLocation = false
 self.mapView.showsUserLocation = true

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文