【问题标题】:MKMapView MKPointAnnotation tap eventMKMapView MKPointAnnotation 点击​​事件
【发布时间】:2013-02-23 21:33:50
【问题描述】:

我有一个注释列表 (MKPointAnnotation)。我有一个用于整个视图的 UIViewController, MKMapView 实现控制器,我认为这对于检测用户与地图的交互很有用,我自己的 MKPointAnnotation 实现(子类)控制器告诉如何显示注释。

但是,我对用户检测到点击事件感到震惊。

谷歌搜索告诉我,我必须通过实现以下功能来做一些事情。

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control

而且我必须在一些实现 MapViewDelegate(协议)的类中实现这一点。

但我很困惑,无法继续前进。谁能告诉我在哪里做什么?

对不起!

【问题讨论】:

  • 您必须为每个注释设置标签,以便当您点击任何注释时,您可以从注释中获取标签并调用数组的相应数据成员生成这些注释。
  • - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { NSLog(@"got here"); .....我把这个函数放在所有三个控制器中,但没有一个被调用......你能告诉我应该在哪里定义这个函数吗?

标签: ios objective-c mkmapview mapkit mkannotation


【解决方案1】:

有两种方法可以检测用户与您的注释视图的交互。常见的技术是为您的MKAnnotationView 定义一个标注(当您在典型地图应用程序中点击图钉时看到的标准小弹出气泡)。然后你在标准的viewForAnnotation 方法中为你的注解创建注解视图:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
    annotationView.canShowCallout = YES;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

    return annotationView;
}

通过这样做,您会得到一个标注,但您正在添加一个正确的附件,在我上面的示例中,它是一个披露指示器。这样,他们点击您的注释视图(在我上面的示例中,地图上的一个图钉),他们会看到标注,当他们点击该标注的正确附件(本示例中的小披露指示器)时,您的 calloutAccessoryControlTapped被调用(在我下面的示例中,对某些细节视图控制器执行 segue):

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    [self performSegueWithIdentifier:@"DetailsIphone" sender:view];
}

这是 iPhone 小屏幕上非常典型的用户体验。

但是,如果您不喜欢该 UX 并且您不想要标准标注,而是希望发生其他事情,您可以定义 MKAnnotationView 以便不显示标注,而是您拦截它并做其他事情(例如,在 iPad 地图应用程序上,您可能会显示一些更复杂的弹出框而不是标准标注)。例如,您可以让您的 MKAnnotationView 不显示标注:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];
    annotationView.canShowCallout = NO;

    return annotationView;
}

但是您可以手动处理didSelectAnnotationView 以检测用户何时点击了您的MKAnnotationView,在此示例中显示了一个弹出框:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    [mapView deselectAnnotation:view.annotation animated:YES];

    DetailsViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailsPopover"];
    controller.annotation = view.annotation;
    self.popover = [[UIPopoverController alloc] initWithContentViewController:controller];
    self.popover.delegate = self;
    [self.popover presentPopoverFromRect:view.frame
                                  inView:view.superview
                permittedArrowDirections:UIPopoverArrowDirectionAny
                                animated:YES];
}

我在my answer here 中包含上述代码生成的用户界面的一些屏幕快照。

【讨论】:

  • 嗨,这似乎不适用于 iOS7 及更高版本。对 iOS8 的修复有什么建议吗?
  • @roshi 我对其进行了测试,这在 iOS 8 中运行良好。您是否设置了地图视图的委托?如果您仍然遇到问题,可以在 S.O. 上发布您自己的问题。包含详细的代码示例、您尝试过的内容的描述等。
  • @Rob 你能看看stackoverflow.com/questions/30396754/… 并帮我解决我的问题
  • @Rob 这会将我的用户位置变成一个图钉。我可以防止这种情况吗?以及防止它被点击?
  • @user1282637 检查if ([annotation isKindOfClass:[MKUserLocation class]]) ...,如上面修改后的示例 sn-p 所示。
【解决方案2】:

Swift 3 的 Rob 示例:

class MapViewController: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        // Create map view in storyboard
        view.delegate = self
    }
}

extension MapViewController: MKMapViewDelegate
{
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
    {
        let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "annotationView")
        annotationView.canShowCallout = true
        annotationView.rightCalloutAccessoryView = UIButton.init(type: UIButtonType.detailDisclosure)

        return annotationView
    }

    func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
    {
        guard let annotation = view.annotation else
        {
            return
        }

        let urlString = "http://maps.apple.com/?sll=\(annotation.coordinate.latitude),\(annotation.coordinate.longitude)"
        guard let url = URL(string: urlString) else
        {
            return
        }

        UIApplication.shared.openURL(url)
    }
}

【讨论】:

    【解决方案3】:

    在此方法中添加按钮

    -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation 
    {
      pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
      pinView.canShowCallout = YES;
    }
    
    Then callout method
    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
    {
          InfoView *infoView = [[InfoView alloc]initWithNibName:@"InfoView" bundle:nil];
            [self.navigationController pushViewController:infoView animated:YES];
    
    } 
    

    【讨论】:

    • 你能告诉我应该在哪里实现这些吗? MKMapView 控制器?
    • @RaviVooda yaa 强加于 MapViewpart 的编码。任何其他问题你可以问我:)
    • @RaviVooda 你应该在delegate 中为你的MKMapView 实现这些。您经常将delegateMKMapView 指定为具有地图视图的视图的视图控制器。但不要忘记设置地图视图的委托(在代码中或通过 Interface Builder)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 2012-05-17
    相关资源
    最近更新 更多