88

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

我有一个正在使用的自定义注释视图,我想使用 image 属性在地图上用我自己的图标显示该点。我有这个工作正常。但我还想做的是覆盖默认标注视图(触摸注释图标时显示标题/副标题的气泡)。我希望能够控制标注本身:mapkit 仅提供对左右辅助标注视图的访问,但无法为标注气泡提供自定义视图,或将其设为零大小或其他任何内容。

我的想法是在 my 中覆盖 selectAnnotation/deselectAnnotation MKMapViewDelegate,然后通过调用我的自定义注释视图来绘制我自己的自定义视图。这有效,但仅在我的自定义注释视图类canShowCallout中设置为时。YES如果我将此设置为NO(这是我想要的,因此不会绘制默认标注气泡),则不会调用这些方法。因此,如果没有显示默认标注气泡视图,我无法知道用户是否触摸了我在地图上的点(选择了它)或触摸了不属于我的注释视图的点(选择了它)。

我试着走一条不同的路,自己处理地图中的所有触摸事件,但我似乎无法让它工作。我阅读了与在地图视图中捕获触摸事件相关的其他帖子,但它们并不是我想要的。有没有办法在绘制之前深入地图视图以删除标注气泡?我不知所措。

有什么建议么?我错过了一些明显的东西吗?

4

9 回答 9

54

还有一个更简单的解决方案。

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

然后创建一个子类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...
    }
}

轰隆隆,大功告成。

于 2011-08-05T11:16:40.953 回答
40

细节标注附件查看

在过去,这很痛苦,但 Apple 已经解决了,只需查看MKAnnotationView上的文档

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

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

于 2012-07-23T12:44:23.497 回答
13

继续@TappCandy 非常简单的答案,如果您想以与默认方式相同的方式为气泡设置动画,我制作了这种动画方法:

- (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);
            }];
        }];
    }];
}

它看起来相当复杂,但只要你的标注气泡的点被设计为中心底部,你应该能够替换myBubbleWidthmyBubbleHeight使用你自己的尺寸来让它工作。并记住确保您的子视图将其autoResizeMask属性设置为 63(即“全部”),以便它们在动画中正确缩放。

:-乔

于 2011-10-24T12:41:51.993 回答
8

发现这对我来说是最好的解决方案。您必须使用一些创造力来进行自己的自定义

在您的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是 a UICalloutView,那么您可以随意使用它,以及其中的内容。

于 2011-08-31T20:36:46.700 回答
6

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

只是在MKMapViewDelegate这里使用对您没有帮助,子类MKMapView化和尝试扩展现有功能也对我不起作用。

我最终做的是创建我自己的CustomCalloutView,我在我的MKMapView. 您可以以任何您想要的方式设置此视图的样式。

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

它接受一个MKAnnotation对象并设置自己的标题,然后调用另外两个非常难看的方法,调整标注内容的宽度和大小,然后在正确的位置围绕它绘制对话气泡。

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

解决所有这些问题需要一些时间,但现在标注几乎就像官方标注一样,但我有自己的风格。

于 2009-10-16T10:35:13.873 回答
5

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

我能够通过以下方式实现这些:a) 将 canShowCallout 设置为 NO b) 子类化、MKPinAnnotationView 并覆盖 touchesBegan 和 touchesEnd 方法。

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

于 2009-11-20T11:22:24.777 回答
3

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

  // 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 是UIView大小为 320x100 的 - showCallout 是 BOOL -[self animateIn];是查看动画的函数UIAlertView

于 2012-01-26T11:08:28.037 回答
1

You can use leftCalloutView, setting annotation.text to @" "

Please find below the example code:

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 = @" ";            
于 2011-04-14T09:18:18.583 回答
1

我推出了出色的 SMCalloutView 的分支,它通过为标注提供自定义视图并允许灵活的宽度/高度非常轻松地解决了这个问题。仍然有一些怪癖需要解决,但到目前为止它非常实用:

https://github.com/u10int/calloutview

于 2012-10-17T23:04:09.457 回答