如何自定义MKAnnotationView的标注泡泡?

我目前正在使用mapkit,并卡住了。

我有一个自定义的注释视图,我正在使用,我想使用图像属性来显示地图上的点与我自己的图标。 我有这个工作正常。 但是我也想要做的是重写默认的标注视图(当标注图标被触摸时,标题/副标题显示的气泡)。 我希望能够自己控制标注:mapkit只提供对左侧和右侧辅助标注视图的访问,但没有办法为标注泡泡提供自定义视图,或者为其提供零大小或其他任何内容。

我的想法是重写我的MKMapViewDelegate selectAnnotation / deselectAnnotation,然后通过调用我的自定义注释视图来绘制自己的自定义视图。 这工作,但只有当我的自定义注释视图类中canShowCallout设置为YES 。 这些方法不会被调用,如果我把这个设置为NO (这是我想要的,所以默认的标注泡泡没有绘制)。 所以我无法知道用户是否触摸到了我在地图上的点(选中它),或者触摸了一个不是我的注释视图的一部分的点(取而代之),而没有显示默认的标注泡泡视图。

我试着走了一条不同的路,只是在地图上自己处理所有的触摸事件,我似乎无法得到这个工作。 我在地图视图中阅读了与捕捉触摸事件相关的其他post,但它们并不完全是我想要的。 有没有办法在绘图前挖掘地图视图以去除标注泡泡? 我不知所措

有什么build议么? 我错过了什么明显的?

有一个更简单的解决scheme。

创build一个自定义UIView (为您的标注)。

然后创build一个MKAnnotationView的子类并覆盖setSelected ,如下所示:

 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if(selected) { //Add your custom view to self... } else { //Remove your custom view... } } 

繁荣,工作完成。

detailCalloutAccessoryView

在过去这是一个痛苦,但苹果已经解决了它,只需检查MKAnnotationView上的文档

 view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) view.canShowCallout = true view.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "zebra")) 

真的,就是这样。 接受任何UIView。

继续从@ TappCandy的非常简单的答案,如果你想以默认的方式animation你的泡泡,我已经制作了这个animation方法:

 - (void)animateIn { float myBubbleWidth = 247; float myBubbleHeight = 59; calloutView.frame = CGRectMake(-myBubbleWidth*0.005+8, -myBubbleHeight*0.01-2, myBubbleWidth*0.01, myBubbleHeight*0.01); [self addSubview:calloutView]; [UIView animateWithDuration:0.12 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^(void) { calloutView.frame = CGRectMake(-myBubbleWidth*0.55+8, -myBubbleHeight*1.1-2, myBubbleWidth*1.1, myBubbleHeight*1.1); } completion:^(BOOL finished) { [UIView animateWithDuration:0.1 animations:^(void) { calloutView.frame = CGRectMake(-myBubbleWidth*0.475+8, -myBubbleHeight*0.95-2, myBubbleWidth*0.95, myBubbleHeight*0.95); } completion:^(BOOL finished) { [UIView animateWithDuration:0.075 animations:^(void) { calloutView.frame = CGRectMake(-round(myBubbleWidth/2-8), -myBubbleHeight-2, myBubbleWidth, myBubbleHeight); }]; }]; }]; } 

它看起来相当复杂,但是只要你的标注泡泡的点被devise为中心底部,你应该能够用你自己的大小replacemyBubbleWidthmyBubbleHeight来使其工作。 记住要确保你的子视图的autoResizeMask属性设置为63(即“全部”),以便它们在animation中正确缩放。

:-Joe

发现这对我来说是最好的解决scheme。 你将不得不用一些创造力来做自己的定制

在你的MKAnnotationView子类中,你可以使用

 - (void)didAddSubview:(UIView *)subview{ int image = 0; int labelcount = 0; if ([[[subview class] description] isEqualToString:@"UICalloutView"]) { for (UIView *subsubView in subview.subviews) { if ([subsubView class] == [UIImageView class]) { UIImageView *imageView = ((UIImageView *)subsubView); switch (image) { case 0: [imageView setImage:[UIImage imageNamed:@"map_left"]]; break; case 1: [imageView setImage:[UIImage imageNamed:@"map_right"]]; break; case 3: [imageView setImage:[UIImage imageNamed:@"map_arrow"]]; break; default: [imageView setImage:[UIImage imageNamed:@"map_mid"]]; break; } image++; }else if ([subsubView class] == [UILabel class]) { UILabel *labelView = ((UILabel *)subsubView); switch (labelcount) { case 0: labelView.textColor = [UIColor blackColor]; break; case 1: labelView.textColor = [UIColor lightGrayColor]; break; default: break; } labelView.shadowOffset = CGSizeMake(0, 0); [labelView sizeToFit]; labelcount++; } } } } 

如果subview是一个UICalloutView ,那么你可以拧它,它里面有什么。

我有同样的问题。 在这个博客http://spitzkoff.com/craig/?p=81上有很多关于这个话题的博客文章。;

只是使用MKMapViewDelegate没有帮助你在这里和MKMapView并试图扩展现有的function也没有为我工作。

我最终做的是创build我自己的CustomCalloutView ,我在我的MKMapView之上。 你可以用任何你想要的方式来devise这个视图。

我的CustomCalloutView有一个类似于这个的方法:

- (void) openForAnnotation: (id)anAnnotation { self.annotation = anAnnotation; // remove from view [self removeFromSuperview]; titleLabel.text = self.annotation.title; [self updateSubviews]; [self updateSpeechBubble]; [self.mapView addSubview: self]; }
- (void) openForAnnotation: (id)anAnnotation { self.annotation = anAnnotation; // remove from view [self removeFromSuperview]; titleLabel.text = self.annotation.title; [self updateSubviews]; [self updateSpeechBubble]; [self.mapView addSubview: self]; } 

它需要一个MKAnnotation对象并设置它自己的标题,然后调用其他两个非常难看的方法来调整标注内容的宽度和大小,然后在正确的位置上绘制MKAnnotation

最后,视图被添加为mapView的子视图。 这个解决scheme的问题在于,当地图视图滚动时很难将标注保持在正确的位置。 我只是隐藏在地图视图的委托方法的区域更改解决这个问题的标注。

解决所有这些问题花费了一些时间,但现在标注差不多像官方的那样,但是我有自己的风格。

基本上要解决这个问题,需要:a)防止默认的标注泡泡出现。 b)找出哪个注释被点击。

我能够实现这些:a)设置canShowCallout为NO b)inheritance,MKPinAnnotationView并覆盖touchesBegan和touchesEnd方法。

注意:您需要处理MKAnnotationView而不是MKMapView的触摸事件

我只是想出一个办法,这里的想法是

  // Detect the touch point of the AnnotationView ( i mean the red or green pin ) // Based on that draw a UIView and add it to subview. - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view]; // NSLog(@"regionWillChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y); [testview setCenter:CGPointMake(newPoint.x+5,newPoint.y-((testview.frame.size.height/2)+35))]; [testview setHidden:YES]; } - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view]; // NSLog(@"regionDidChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y); [testview setCenter:CGPointMake(newPoint.x,newPoint.y-((testview.frame.size.height/2)+35))]; [testview setHidden:NO]; } - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { NSLog(@"Select"); showCallout = YES; CGPoint point = [self.mapView convertPoint:view.frame.origin fromView:view.superview]; [testview setHidden:NO]; [testview setCenter:CGPointMake(point.x+5,point.y-(testview.frame.size.height/2))]; selectedCoordinate = view.annotation.coordinate; [self animateIn]; } - (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view { NSLog(@"deSelect"); if(!showCallout) { [testview setHidden:YES]; } } 

这里 – testview是一个大小为320×100的UIView – showCallout是BOOL – [self animateIn]; 是像UIAlertView一样查看animation的函数。

您可以使用leftCalloutView,将annotation.text设置为@“”

请在下面find示例代码:

 pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID]; if(pinView == nil){ pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease]; } CGSize sizeText = [annotation.title sizeWithFont:[UIFont fontWithName:@"HelveticaNeue" size:12] constrainedToSize:CGSizeMake(150, CGRectGetHeight(pinView.frame)) lineBreakMode:UILineBreakModeTailTruncation]; pinView.canShowCallout = YES; UILabel *lblTitolo = [[UILabel alloc] initWithFrame:CGRectMake(2,2,150,sizeText.height)]; lblTitolo.text = [NSString stringWithString:ann.title]; lblTitolo.font = [UIFont fontWithName:@"HelveticaNeue" size:12]; lblTitolo.lineBreakMode = UILineBreakModeTailTruncation; lblTitolo.numberOfLines = 0; pinView.leftCalloutAccessoryView = lblTitolo; [lblTitolo release]; annotation.title = @" "; 

我已经推出了优秀的SMCalloutView的叉子,解决了问题,提供了一个自定义视图的标注,并允许灵活的宽度/高度非常轻松。 仍然有一些怪癖,但它是非常有用的到目前为止:

https://github.com/u10int/calloutview