4

我试图MKMapView在选择注释后居中。我也启用canShowCallout了,但似乎 iOS 首先显示标注(当它不适合屏幕时移动)然后移动地图,导致标注在屏幕上不完全可见。

标注位置不正确

在渲染和显示标注的位置之前,如何使地图居中?

4

2 回答 2

4

我想完成同样的事情并最终做了以下事情。

在开始之前请注意:我知道解决方案非常丑陋!...但是,嘿,它有效。

注意:我的目标是 iOS 9,但它应该适用于早期版本的 iOS:

好的,我们开始:

  • 首先,在您的视图控制器中创建一个新属性,例如:@property(nonatomic, assign, getter=isPinCenteringOngoing) BOOL pinCenteringOngoing;
  • 为您的annotationViewsmapView:viewForAnnotation:设置canShowCalloutNO
  • mapView:didSelectAnnotationView:执行以下操作:

    - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
    {
        if([view isKindOfClass:$YOURANNOTATIONVIEWCLASS$.class])
        {
            if(!self.isPinCenteringOngoing)
            {
                self.pinCenteringOngoing = YES;
                [self centerMapOnSelectedAnnotationView:($YOURANNOTATIONVIEWCLASS$ *)view];
            }
            else
            {
                self.pinCenteringOngoing = NO;
            }
        }
    }
    
  • mapView:didDeselectAnnotationView:执行以下操作:

    - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
    {
        if([view isKindOfClass:$YOURANNOTATIONVIEWCLASS$.class])
        {
            if(!self.isPinCenteringOngoing)
            {
                view.canShowCallout = NO;
            }
        }
    }
    
  • 最后创建一个执行实际工作的新方法:

    - (void)centerMapOnSelectedAnnotationView:($YOURANNOTATIONVIEWCLASS$ *)view
    {
        // Center map
        CGPoint annotationCenter = CGPointMake(CGRectGetMidX(view.frame), CGRectGetMidY(view.frame));
        CLLocationCoordinate2D newCenter = [self.mapView convertPoint:annotationCenter toCoordinateFromView:view.superview];
        [self.mapView setCenterCoordinate:newCenter animated:YES];
    
        // Allow callout to be shown
        view.canShowCallout = YES;
    
        // Deselect and then select the annotation so the callout is actually displayed
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void)
        {
            [self.mapView deselectAnnotation:view.annotation animated:NO];
    
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void)
            {
                [self.mapView selectAnnotation:view.annotation animated:NO];
            });
        });
    }
    

为了完成我的回答,这里是我在上面的代码中所做的事情以及我这样做的原因的文字说明:

  • 我想要的是注释在屏幕上居中,标注在其上方居中。
  • 我默认得到的是:
    • 选择注释时,地图会打开标注,并在必要时调整地图以使标注适合屏幕。该标准实现绝不保证标注在注释上方“居中”。
    • 通过 setCenterCoordinate: 使地图居中,注释视图在地图上居中。
    • 现在,前两个点结合起来可能会导致标注被“切断”,因为注释在地图上居中,但标注不在注释上方居中。
  • 为了解决这个问题,我执行以下操作:
    • 首先,我禁用默认情况下显示的标注,将每个 annotationView 的 canShowCallout 设置为 NO
    • 当用户选择注释时,我首先将地图居中
    • 然后我允许显示标注,将所选注释的 canShowCallout 设置为 YES
    • 然后我取消选择然后再次选择注释,因此实际上显示了标注
    • 为了使标注在注释上方正确居中,我需要稍微延迟取消选择/选择,以便地图居中可以完成

我希望我的回答可能有用。

于 2016-07-02T01:10:16.817 回答
1

这是另一个解决方案:

  1. var selectFirstAnnotation = false在控制器中创建一个新的布尔属性

  2. 在注释居中之前将其设置为 true

  3. 添加这是在regionDidChangeAnimated.

    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
            if selectFirstAnnotation == true {
              if let annotation = mapView.annotations.first(where: { !($0 is MKUserLocation) }) {
                mapView.selectAnnotation(annotation, animated: true)
                selectFirstAnnotation = false
        }}}
    

适合我的行为

于 2017-11-27T15:55:29.647 回答