5

enter image description here

i am using mapkit how i can multiple line in MKAnnotation view.

Every annotation there has title and subtitle. how i show sub title with multiple line with the help of auto layout ?

i found it's Answer .plz try my answer. we just need to do code in

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

}

here i show the idea how to use autolayout with MKAnnotation .

balkaran singh
  • 2,754
  • 1
  • 17
  • 32
  • Possible duplicate of [How to display 2 lines of text for subtitle of MKAnnotation and change the image for the button on the right?](http://stackoverflow.com/questions/5831382/how-to-display-2-lines-of-text-for-subtitle-of-mkannotation-and-change-the-image) – Jeyamahesan Oct 24 '16 at 09:48
  • @Jeyamahesan i only post this question to give idea how to use autolayout with mkannotation. – balkaran singh Oct 24 '16 at 09:50
  • already you have answered (http://stackoverflow.com/a/39160132/6176024) the similar type of question with the same answer and code snippet given in this answer. – Jeyamahesan Oct 24 '16 at 09:54
  • @Jeyamahesan no one give any attention on that answer . buz that questions post in 2011 . that time autolayout not available . i only what help other people with my code. – balkaran singh Oct 24 '16 at 09:58

6 Answers6

14

we can show multiple line in MKAnnotation view With the help of auto layout

it's very simple.

in objective c

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

output

enter image description here

For Swift

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

        let identifier = "MyPin"

        if annotation.isKindOfClass(MKUserLocation) {
            return nil
        }

        var annotationView: MKPinAnnotationView? = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView

        if annotationView == nil {

            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView?.canShowCallout = true

              let label1 = UILabel(frame: CGRectMake(0, 0, 200, 21))
            label1.text = "Some text1 some text2 some text2 some text2 some text2 some text2 some text2"
             label1.numberOfLines = 0
              annotationView!.detailCalloutAccessoryView = label1;

            let width = NSLayoutConstraint(item: label1, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.LessThanOrEqual, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 200)
            label1.addConstraint(width)


            let height = NSLayoutConstraint(item: label1, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 90)
            label1.addConstraint(height)



        } else {
            annotationView!.annotation = annotation
        }
        return annotationView
    }


}

enter image description here

here i use NSLayoutConstraint

i programatically create a label. add the constraint on it and then add the label in detailCalloutAccessoryView of MKAnnotationView.

balkaran singh
  • 2,754
  • 1
  • 17
  • 32
11

extension for adding multiple lines:

import MapKit // must import MapKit for MKAnnotationView to get recognized

extension MKAnnotationView {

    func loadCustomLines(customLines: [String]) {
        let stackView = self.stackView()
        for line in customLines {
            let label = UILabel()
            label.text = line
            stackView.addArrangedSubview(label)
        }
        self.detailCalloutAccessoryView = stackView
    }



    private func stackView() -> UIStackView {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        stackView.alignment = .fill
        return stackView
    }
}

using:

view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.loadCustomLines(customLines: ["qqqq", "wwww", "eee"])
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
Igor Azarov
  • 164
  • 1
  • 5
1

Using auto layout you can type something like:

let subtitleLabel = UILabel()
subtitleLabel.text = "Location updated\n" + dateFormatter.string(from: date)
subtitleLabel.numberOfLines = 0
subtitleLabel.font = UIFont.systemFont(ofSize: 14)
subtitleLabel.textColor = .lightGray
subtitleLabel.setContentCompressionResistancePriority(.required, for: .vertical)

annotationView?.detailCalloutAccessoryView = subtitleLabel
Roman Filippov
  • 2,289
  • 2
  • 11
  • 17
  • Using `setContentCompressionResistancePriority()` seems to be the shortest way to do this. Also, could probably use Dynamic Type support with `subtitleLabel.font = UIFont.preferredFont(forTextStyle: .body); subtitleLabel.adjustsFontForContentSizeCategory = true`. – Gary Oct 11 '18 at 09:03
1

5 steps

I created a label and added it to the annotationView?.detailCalloutAccessoryView property (step 5). I also set the label's text to the annotation.subtitle text (step 2 & step 4) and .numberOfLines = 0

Steps are in the comments above the code

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

    } else {
        annotationView!.annotation = annotation
    }

    return annotationView
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
0

And If you want to have the multi label clicked to go somewhere, you would need to: 1- create programmatically created UITapGestureRecognizer on the AnnotationView. 2- create the function to pass to the gesture selector. The function takes a sender parameter of type UIGestureRecognizer. Have an if statement that makes sure that you have the canshowcallout to true so you only click when it's showing to avoid clicking on the actual pin itself.

So in my case i had this scenario. This may help someone: - tableView that has cells of different locations populated - top half of the screen is map that shows your the pin of each location - As you click on the table view or the pins in the map, the map center itself and shows you the pin callout view, which is a small view with a picture and the name of the location in multi-lines breaks if the name of location is long to avoid truncating tails. - Because the index was passed and used everywhere in our code to determine the which location was clicked , i had to use it also to show the right name in the callout of the location that was clicked. The problem that i was having is the click on the label since i used annotationView.detailCalloutAccessoryView = myLabel . seems like when . you use the detail one and not the right or left, you don't get the click even from the controlTapped map delegate function. So i had to do the following inside the gesture selector function i talked about previously: make sure that you are doing somekind of guard or if let with comma on these checks all together. - check for the view tag by doing let tag = sender.view.tag - get the view as MKPinAnnotationView: let view = sender.view as? MKPointAnnotationView - check for callout to make sure it's showing first by doing: view.canShowCallout - then inside the curly braces of the if or guard you do let index = tag and pass in the index to my function that perform the action on the view to segue to the native apple map after clicking on the annotationView.

  • after all that in annotationFor View delegate function as i said before pass in this function to the gesture recognizer selector
YB88
  • 3
  • 2
0
let label1 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
label1.text = "Some text1 some text2 some text2 some text2 some text2 some text2 some text2"
label1.numberOfLines = 0
annotationView!.detailCalloutAccessoryView = label1;

let width = NSLayoutConstraint(item: label1, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 200)
        label1.addConstraint(width)


let height = NSLayoutConstraint(item: label1, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 90)
        label1.addConstraint(height)
Taimoor Suleman
  • 1,588
  • 14
  • 29