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
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)
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
}
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.
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
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
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
}
}
here i use NSLayoutConstraint
i programatically create a label. add the constraint on it and then add the label in detailCalloutAccessoryView of MKAnnotationView.
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"])