MapKit 在 XCode 4.6 中滚动地图时更改注释视图顺序

Posted

技术标签:

【中文标题】MapKit 在 XCode 4.6 中滚动地图时更改注释视图顺序【英文标题】:MapKit changes annotation view order when map is scrolled in XCode 4.6 【发布时间】:2013-05-08 04:06:02 【问题描述】:

我是一位经验丰富的 ios 开发人员,但这确实让我感到难过。我正在同时向 Apple 提交问题报告。

我正在向 MKMapKit 地图 (Xcode 4.6) 添加注释。每个注解都是一个 MyAnnotation 类; MyAnnotation 定义了一个属性 location_id,我用它来跟踪该注释。

问题很简单:我希望 location_id 为 -1 的 MyAnnotation 出现在其他所有内容的前面。

为此,我在我的 MKMapViewDelegate 中覆盖 mapView:didAddAnnotationViews::

-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views 


// Loop through any newly added views, arranging them (z-index)
for (MKAnnotationView* view in views) 

    // Check the location ID
    if([view.annotation isKindOfClass:[MyAnnotation class]] && [((MyAnnotation*)(view.annotation)).location_id intValue]==-1 ) 

        // -1: Bring to front
        [[view superview] bringSubviewToFront:view];
        NSLog(@"to FRONT: %@",((MyAnnotation*)view.annotation).location_id);

     else 

        // Something else: send to back
        [[view superview] sendSubviewToBack:view];
        NSLog(@"to BACK: %@",((MyAnnotation*)view.annotation).location_id);
    


这很好用。我有一个“添加”按钮,可以将注释添加到地图中心附近的随机位置。每次我按下“添加”按钮时,都会出现一个新注释;但没有任何东西隐藏 location_id 为 -1 的注释。

**直到**我滚动!

当我开始滚动时,我的所有注释都会重新排列(z 顺序),并且我的仔细堆叠不再适用。

真正令人困惑的是,我之前已经完成了图标顺序堆叠,没有任何问题。我创建了一个全新的单视图应用程序来测试这个问题;将 MKAnnotationView 项目发送到后面或前面仅在您滚动之前有效。除了上面描述的代码之外,这个骨架应用程序中没有其他内容。我想知道最新的 MapKit 框架中是否存在某种错误。

最初的问题是在用户滚动时尝试添加新的注释 (mapView:regionDidChangeAnimated:)。注释添加; mapView:didAddAnnotationViews: 代码触发;然后订单被框架中一只看不见的手打乱(大概是在卷轴完成时)。

如果你有兴趣,这里是我的 viewForAnnotation:

-(MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation 


// Is this an A91Location?
if([annotation isKindOfClass:[MyAnnotation class]])

    MyAnnotation* ann=(MyAnnotation*)annotation;

    NSLog(@"viewForAnnotation with A91Location ID %@",ann.location_id);


    if([ann.location_id intValue]==-1)

        // If the ID is -1, use a green pin
        MKPinAnnotationView* green_pin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
        green_pin.pinColor=MKPinAnnotationColorGreen;
        green_pin.enabled=NO;
        return green_pin;

     else 

        // Otherwise, use a default (red) pin
        MKPinAnnotationView* red_pin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
        red_pin.enabled=NO;
        return red_pin;
    



// Everything else
return nil;



还有我的班级:

@interface MyAnnotation : NSObject <MKAnnotation>

@property (strong, nonatomic, readonly) NSNumber* location_id;
@property (strong, nonatomic, readonly) NSString*  name;
@property (strong, nonatomic, readonly) NSString*  description;
@property (nonatomic) CLLocationCoordinate2D coordinate;

-(id) initWithID:(NSNumber*)location_id name: (NSString*) name description:(NSString*) description location:(CLLocationCoordinate2D) location;

// For MKAnnotation protocol... return name and description, respectively
-(NSString*)title;
-(NSString*)subtitle;

@end

【问题讨论】:

看来我不是唯一一个遇到这种情况的人:devforums.apple.com/message/743974#743974 对一个完美记录的问题投赞成票。确实似乎只有 hacky-ish 解决问题的方法,而且 Apple 没有提供任何官方 API 来管理 MKAnnotationViews 的 z 排序! 【参考方案1】:

您是否可以尝试以下解决方法:

1) 删除 mapView:didAddAnnotationViews 中的代码:

2) 移动或捏合地图时拾取(我认为这是您认为的滚动,对吗?) - 我使用手势而不是 mapView regionChanged 来执行此操作,因为我有过不好的经历,例如无法解释的行为后者。

//recognise the paning gesture to fire the didDragMap method
UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self     action:@selector(didDragMap:)];
[panRec setDelegate:self];
[self.mapView addGestureRecognizer:panRec];

//recognise the pinching gesture to fire the didPinchMap method
UIPinchGestureRecognizer *pinchRec = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(didPinchMap:)];
[pinchRec setDelegate:self];
//[pinchRec setDelaysTouchesBegan:YES];
[self.mapView addGestureRecognizer:pinchRec];

//recognise the doubleTap
UITapGestureRecognizer *doubleTapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPinchMap:)];
[doubleTapRec setDelegate:self];
doubleTapRec.numberOfTapsRequired = 2;
[self.mapView addGestureRecognizer:doubleTapRec];

3) 编写一个自定义的“plotAnnotations”函数来显示您的注释。此函数将遍历所有注释并将它们保存在按您的位置 ID DESC 排序的数组“annotationsToShow”中,以便最后添加您的 location_id -1。使用 [self.mapView addAnnotations:annotationsToShow];显示它们。

4) 在你的gestureRecognizer函数中调用plotAnnotations

- (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer 
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
        [self plotAnnotations];
    


- (void)didPinchMap:(UIGestureRecognizer*)gestureRecognizer 
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
        [self plotAnnotations];
    

5) 在 3) [self.mapView removeAnnotations:annotationsToRemove]; 中显示新注释之前,您可能需要删除所有注释;

【讨论】:

以上是关于MapKit 在 XCode 4.6 中滚动地图时更改注释视图顺序的主要内容,如果未能解决你的问题,请参考以下文章

Swift mapkit未指向位置

iPhone Mapkit 蓝点/用户位置区域缩放问题

蓝点位置地图包

滚动 mapView 或点击标记时,如何创建具有自定义注释和区域焦点的地图?

在 iOS MapKit 中,如何在地图旋转时为注释设置动画?

不知道如何在 SwiftUI (Xcode 12.4) 中打开地图