如何为MKAnnotation的字幕显示2行文本并更改右侧按钮的图像?

时间:2011-04-29 11:25:49

标签: iphone mkmapview mkannotation

我正在查看Apple的MapCallouts示例,用于地图注释和标注(==当您点击图钉时出现的气泡)。 每个注释都有坐标,标题和副标题。 我想用2行显示字幕,我试过:

- (NSString *)subtitle
{
return @"Founded: June 29, 1776\nSecond line text";
}

但文字“第二行文字”保留在一行中并使气泡更宽。我明白了:

enter image description here

我还想将按钮的图像更改为我自己的图像,设置按钮的代码目前是这样的:

UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

有什么想法吗?

编辑:我尝试了7KV7的建议。按钮更改成功,但我仍然无法获得2行字幕。 我的代码:

MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
                                        initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier] autorelease];
        customPinView.pinColor = MKPinAnnotationColorPurple;
        customPinView.animatesDrop = YES;


        // Button
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(0, 0, 23, 23);
        button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
        button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

        //UIEdgeInsets titleInsets = UIEdgeInsetsMake(7.0, -20.0, 7.0, 7.0);
        //button.titleEdgeInsets = titleInsets;

        [button setImage:[UIImage imageNamed:@"ic_phone_default.png"] forState:UIControlStateNormal];
        //[button setImage:[UIImage imageNamed:@"ic_phone_selected.png"] forState:UIControlStateSelected];
        [button setImage:[UIImage imageNamed:@"ic_phone_selected.png"] forState:UIControlStateHighlighted];
        [button addTarget:self action:@selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];

        customPinView.rightCalloutAccessoryView = button;

        //two labels
        UIView *leftCAV = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,50)];
        //[leftCAV addSubview : button];
        UILabel *l1=[[UILabel alloc] init];
        l1.frame=CGRectMake(0, 15, 50, 50);
        l1.text=@"First line of subtitle"; 
        l1.font=[UIFont fontWithName:@"Arial Rounded MT Bold" size:(10.0)];

        UILabel *l2=[[UILabel alloc] init];
        l2.frame=CGRectMake(0, 30, 50, 50);
        l2.text=@"Second line of subtitle";
        l2.font=[UIFont fontWithName:@"Arial Rounded MT Bold" size:(10.0)];
        [leftCAV addSubview : l1];
        [leftCAV addSubview : l2];
        customPinView.leftCalloutAccessoryView = leftCAV;
        //customPinView.
        customPinView.canShowCallout = YES;

        return customPinView;

我明白了:

enter image description here

8 个答案:

答案 0 :(得分:5)

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{   
    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"loc"];

    // Button
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 23, 23);
button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

[button setImage:[UIImage imageNamed:yourImageName] forState:UIControlStateNormal];
[advertButton addTarget:self action:@selector(buttonPress:) forControlEvents:UIControlEventTouchUpInside];

annView.rightCalloutAccessoryView = button;


    // Image and two labels
    UIView *leftCAV = [[UIView alloc] initWithFrame:CGRectMake(0,0,23,23)];
    [leftCAV addSubview : yourImageView];
    [leftCAV addSubview : yourFirstLabel];
    [leftCAV addSubview : yourSecondLabel];
    annotationView.leftCalloutAccessoryView = leftCAV;

    annotationView.canShowCallout = YES;

    return pin;
}

<强>更新

注释的默认样式仅支持标题和副标题。标题和副标题都不能包含换行符。如果没有子类化,你就无法做到这一点。

要使用自定义视图,请查看Apple的示例代码:

http://developer.apple.com/library/ios/#samplecode/WeatherMap/Introduction/Intro.html

我也认为您的代码存在问题

UILabel *l1=[[UILabel alloc] init];
l1.frame=CGRectMake(0, 15, 50, 50);
l1.text=@"First line of subtitle"; 
l1.font=[UIFont fontWithName:@"Arial Rounded MT Bold" size:(10.0)];

UILabel *l2=[[UILabel alloc] init];
l2.frame=CGRectMake(0, 30, 50, 50);
l2.text=@"Second line of subtitle";
l2.font=[UIFont fontWithName:@"Arial Rounded MT Bold" size:(10.0)];
[leftCAV addSubview : l1];
[leftCAV addSubview : l2];

l1具有框架(0,15,50,50)并且l2具有(0,30,50,50)。这两个不重叠吗?我的意思是l1将从y = 15开始,高度为50.所以当l2从30开始时它可能会重叠..你可以通过改变帧来检查

答案 1 :(得分:5)

使用此

 - (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

        if ([annotation isKindOfClass:[MKUserLocation class]])
            return nil;
        if ([annotation isKindOfClass:[CustomAnnotation class]]) {
            CustomAnnotation *customAnnotation = (CustomAnnotation *) annotation;

            MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomAnnotation"];

            if (annotationView == nil)
                annotationView = customAnnotation.annotationView;
            else
                annotationView.annotation = annotation;

            //Adding multiline subtitle code 

            UILabel *subTitlelbl = [[UILabel alloc]init];
            subTitlelbl.text = @"sri ganganagar this is my home twon.sri ganganagar this is my home twon.sri ganganagar this is my home twon.  ";

            annotationView.detailCalloutAccessoryView = subTitlelbl;

            NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:subTitlelbl attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:150];

             NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:subTitlelbl attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0];
            [subTitlelbl setNumberOfLines:0];
            [subTitlelbl addConstraint:width];
            [subTitlelbl addConstraint:height];




            return annotationView;
        } else
            return nil;
    }

enter image description here

答案 2 :(得分:3)

这是我在没有继承注释视图或使用未记录的API的情况下实现它的方法:

MKAnnotationView* pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];

// Add a custom view to the the callout to allow mutli-line text
UIView *calloutView = [[UIView alloc] initWithFrame:CGRectMake(0, 10, 250, 250)];
UIView *calloutViewHeight = [[UIView alloc] initWithFrame:CGRectMake(0, 10, 1, 250)]; // The reason for this will become apparent below
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 250, 21)];
[title setText:<<your single-line title text>>];
[calloutView addSubview:title];
UILabel *subtitle = [[UILabel alloc] initWithFrame:CGRectMake(10, 35, 250, 250)];
[subtitle setNumberOfLines:0];
[subtitle setText:<<your multi-line title text>>];
CGSize subtitleSize = [subtitle sizeThatFits:CGSizeMake(250, 250)];
[subtitle setFrame:CGRectMake(10, 35, 250, subtitleSize.height)];
[calloutView addSubview:subtitle];
[calloutView setFrame:CGRectMake(0, 10, 250, 35+subtitleSize.height+10)];
[calloutViewHeight setFrame:CGRectMake(0, 0, 1, 35+subtitleSize.height+10)];
pinView.leftCalloutAccessoryView = calloutView;
pinView.rightCalloutAccessoryView = calloutViewHeight;  // The height of the callout is calculated by the right accessory *not* the left, so this fake view is required

您可以相应地调整titlesubtitle来自定义文字的字体/颜色。

当然它有点像黑客,但它可以在没有子类化的情况下实现理想的结果,并且允许您使用您想要添加calloutView的任何其他按钮/图像进行自定义(和您一样)如果您愿意,仍然可以将按钮放在右侧附件视图中,只要您保持高度。)

答案 3 :(得分:2)

如果不进入不受支持的API,则无法完成标注中的两行。如果您这样做,您的应用将被拒绝。

如果您有iPad,则可以看到自定义标注的示例。他们的标注转换为弹出视图,以与标注相同的方式粘贴到地图位置。因此,在下一版iOS中,Apple可能会扩展标注API。现在你只能使用一行字幕。

如果你真的想这样做,你必须制作自己的标注类,并在滚动时使其粘贴到地图上。这可能很难。

另一个想法是伪造标注。创建包含2个视图的自定义注释视图。第一个是地图引脚。第二个是标注。当引脚接触到触摸时,您可以取消隐藏您的标注视图。它将缺少“pop”动画,但您可以根据需要添加任意数量的行。

我从来没有试过这个,听起来好像有很多细节要做对,但它可能会给你一个开始。

答案 4 :(得分:1)

要设置按钮,您可以使用以下代码

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *x=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"someIdentifier"];
    UIButton *button=[UIButton buttonWithType:UIButtonTypeCustom];
    //set the target, title, image etc.
    [x setRightCalloutAccessoryView:button];
    return [x autorelease];
}

答案 5 :(得分:0)

您将无法使用公共API执行此操作,并且必须重新实现您自己的自定义注释视图。
您可以查看重新实现注释视图但模仿标准iOS视图的代码,然后您可以根据自己的需要进行丰富: http://blog.asolutions.com/2010/09/building-custom-map-annotation-callouts-part-1/

答案 6 :(得分:0)

Result Image

此解决方案设置&#34;合理&#34;文字,希望有用:

斯威夫特3:

import MapKit

extension MKAnnotationView {
func setCustomLines(customLines lines: [String]) {
    if lines.count <= 0 {
        return
    }

    // get longest line
    var longest = NSString()
    if let max = lines.max(by: { $1.characters.count > $0.characters.count }) {
        longest = max as NSString
    }
    else {
        fatalError("Can't get longest line.")
    }

    // get longest text width
    let font = UIFont.systemFont(ofSize: 15.0)
    let width = (longest.size(attributes: [NSFontAttributeName: font])).width

    // get text from lines
    var text = lines.first
    for i in 1..<lines.count {
        text = text! + " " + lines[i]
    }

    // label
    let label = UILabel()
    label.text = text
    label.font = font
    label.numberOfLines = lines.count
    label.textAlignment = .justified

    // set width of label
    let con = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: width)
    label.addConstraint(con)

    self.detailCalloutAccessoryView = label
}
}

答案 7 :(得分:0)

这可以分9个步骤完成。

我创建了一个标签,并将其添加到annotationView?.detailCalloutAccessoryView属性中(步骤5)。我还将标签的文本设置为annotation.subtitle文本(步骤2和步骤4)。我设置了标签的.numberOfLines = 0。这将使字幕扩展,无论需要多少行(如果只需要2行,则将其设置为2行)。

对于按钮,我创建了一个UIButton并将其类型设置为.detailDisclosure(步骤7)。然后,将按钮的image属性设置为我要使用的自定义图像(步骤8)。最后,我将按钮设置为annotationView的.rightCalloutAccessoryView属性(步骤9)。

我还偏移了ationmentView的.calloutOffset属性(步骤6)。 I got the offset from ray wenderlich

步骤在代码上方的注释中

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

    if annotation.isKindOfClass(MKUserLocation) {
        return nil
    }

    let reuseIdentifier = "reuseIdentifier"

    var annotationView = mapView.mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) as? MKPinAnnotationView

    if annotationView == nil {

        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)

        // 1. set the annotationView's canShowCallout property to true
        annotationView?.canShowCallout = true

        // 2. get the subtitle text from the annontation's subtitle property
        let subtitleText = annotation.subtitle ?? "you have no subtitle"

        // 3. create a label for the subtitle text
        let subtitleLabel = UILabel()
        subtitleLabel.translatesAutoresizingMaskIntoConstraints = false

        // 4. set the subtitle's text to the label's text property and number of lines to 0
        subtitleLabel.text = subtitleText
        subtitleLabel.numberOfLines = 0

        // 5. set the annotation's detailCalloutAccessoryView property to the subtitleLabel
        annotationView?.detailCalloutAccessoryView = subtitleLabel

        // 6. offset the annotationView's .calloutOffset property
        annotationView?.calloutOffset = CGPoint(x: -5, y: 5)

        // 7. create a button and MAKE SURE to set it's type to .detailDisclosure or it won't appear
        let button = UIButton(type: .detailDisclosure)

        // 8. set the button's image to whatever custom UIImage your using
        button.setImage(UIImage(named: "yourCustomImage"), for: .normal)

        // 9. set the button to the annotationView's .rightCalloutAccessoryView property
        annotationView?.rightCalloutAccessoryView = button

    } else {
        annotationView!.annotation = annotation
    }

    return annotationView
}