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

Zac*_*ach 89 objective-c mapkit mkmapview mkannotationview ios

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

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

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

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

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

Tap*_*ndy 53

有一个更简单的解决方案.

创建自定义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...
    }
}
Run Code Online (Sandbox Code Playgroud)

热潮,完成工作.

  • 嗨TappCandy!首先,感谢您的解决方案.它确实有效,但是当加载一个视图(我是从一个nib文件中做)时,按钮不起作用.我该怎么做才能让它们正常工作?谢谢 (8认同)
  • 嗯 - 这不行!它取代了地图注释(即引脚)而不是标注"气泡". (6认同)
  • 这不行.MKAnnotationView没有对mapview的引用,因此您在添加自定义标注时遇到了一些问题.例如,您不知道将此作为子视图添加是否会在屏幕外. (2认同)

Cam*_*mer 40

detailCalloutAccessoryView

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

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

真的,就是这样.采取任何UIView.


jow*_*wie 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);
            }];
        }];
    }];
}
Run Code Online (Sandbox Code Playgroud)

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

:-Joe


小智 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++;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果它subview是a UICalloutView,那么你可以用它来解决它内部的问题.


Sas*_*zke 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中.此解决方案的问题在于滚动地图视图时很难将标注保持在正确的位置.我只是在地图视图中隐藏了callout,在一个区域更改上委托方法来解决这个问题.

解决所有这些问题花了一些时间,但现在标注几乎像官方的那样,但我有自己的风格.


小智 5

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

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

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