Ich sehe mir Apples MapCallouts-Beispiel für Kartenanmerkungen und Beschriftungen an (== Blasen, die angezeigt werden, wenn Sie auf eine Stecknadel klicken). Jede Anmerkung dort hat Koordinaten, Titel und Untertitel. Ich möchte Untertitel in 2 Zeilen anzeigen, ich habe versucht mit:
- (NSString *)subtitle
{
return @"Founded: June 29, 1776\nSecond line text";
}
aber der Text "Zweiter Zeilentext" bleibt in einer Zeile und macht die Blase breiter.
Ich möchte auch das Bild der Schaltfläche in ein eigenes ändern. Der Code, mit dem die Schaltfläche festgelegt wird, sieht derzeit folgendermaßen aus:
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
Irgendwelche Ideen?
EDIT: Ich habe 7KV7's Rat versucht. Der Knopfwechsel ist erfolgreich, aber ich kann immer noch keine Untertitel in 2 Zeilen bekommen. Mein Code:
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);
[email protected]"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);
[email protected]"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;
Ich bekomme das:
- (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;
}
UPDATE
Der Standardstil für Anmerkungen unterstützt nur den Titel und den Untertitel. Weder Titel noch Untertitel dürfen Zeilenumbrüche enthalten. Sie können dies nicht ohne Unterklassen tun.
So verwenden Sie einen Beispielcode für eine benutzerdefinierte Ansicht:
http://developer.Apple.com/library/ios/#samplecode/WeatherMap/Introduction/Intro.html
Ich denke auch, dass es ein Problem in Ihrem Code gibt
UILabel *l1=[[UILabel alloc] init];
l1.frame=CGRectMake(0, 15, 50, 50);
[email protected]"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);
[email protected]"Second line of subtitle";
l2.font=[UIFont fontWithName:@"Arial Rounded MT Bold" size:(10.0)];
[leftCAV addSubview : l1];
[leftCAV addSubview : l2];
l1 hat einen Rahmen (0, 15, 50, 50) und l2 hat (0, 30, 50, 50). Überlappen sich diese beiden nicht? Ich meine, l1 fängt bei y = 15 an und hat eine Höhe von 50. Wenn l2 bei 30 anfängt, kann es zu Überlappungen kommen
bitte benutzen Sie dies
- (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;
}
So habe ich es erreicht, ohne die Anmerkungsansicht zu unterteilen oder undokumentierte APIs zu verwenden:
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
Sie können die Schriftart/Farbe des Texts anpassen, indem Sie title
und subtitle
entsprechend anpassen.
Sicher, es ist ein bisschen schwierig, aber es erzielt die gewünschten Ergebnisse ohne Unterklassen und ermöglicht es Ihnen, beliebige zusätzliche Schaltflächen/Bilder hinzuzufügen, die Sie calloutView
hinzufügen möchten wünschen, solange Sie die Höhe behalten).
Zwei Zeilen in einem Callout können nicht ausgeführt werden, ohne auf nicht unterstützte APIs zuzugreifen. In diesem Fall wird Ihre App abgelehnt.
Wenn Sie ein iPad haben, können Sie ein Beispiel für ein benutzerdefiniertes Callout sehen. Ihre Beschriftung verwandelt sich in eine Popout-Ansicht, die wie eine Beschriftung an der Kartenposition haftet. So kann es sein, dass Apple in der nächsten Version von iOS die Callout-API erweitert. Im Moment bleiben Sie bei einzeiligen Untertiteln.
Wenn Sie dies wirklich tun möchten, müssen Sie Ihre eigene Callout-Klasse erstellen und sie beim Scrollen an der Karte festhalten. Das wäre wahrscheinlich schwierig.
Eine andere Idee ist, eine Legende vorzutäuschen. Erstellen Sie eine benutzerdefinierte Anmerkungsansicht mit 2 Ansichten. Der erste ist ein Kartenstift. Die zweite ist eine Legende. Wenn der Stift berührt wird, können Sie die Callout-Ansicht einblenden. Es wird die "Pop" -Animation fehlen, aber Sie können so viele Zeilen einfügen, wie Sie möchten.
Ich habe das noch nie ausprobiert und es hört sich so an, als gäbe es eine Menge Details, um es richtig zu machen, aber es könnte Ihnen einen Anfang geben.
Zum Einstellen der Taste können Sie den folgenden Code verwenden
- (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];
}
Dies kann in 9 Schritten erfolgen.
Ich habe ein Etikett erstellt und es der Eigenschaft annotationView?.detailCalloutAccessoryView
hinzugefügt (Schritt 5). Ich habe auch den Text des Etiketts auf den Text annotation.subtitle
gesetzt (Schritt 2 & Schritt 4). Ich stelle den .numberOfLines = 0
des Etiketts ein. Dadurch wird der Untertitel erweitert, je nachdem, wie viele Zeilen benötigt werden (auf 2 setzen, wenn Sie nur 2 benötigen).
Für die Schaltfläche habe ich einen UIButton erstellt und dessen Typ auf .detailDisclosure
gesetzt (Schritt 7). Anschließend setze ich die Bildeigenschaft der Schaltfläche auf das benutzerdefinierte Bild, das ich verwenden möchte (Schritt 8). Zuletzt habe ich die Schaltfläche auf die Eigenschaft .rightCalloutAccessoryView
von annotationView gesetzt (Schritt 9).
Ich versetze auch die Eigenschaft .calloutOffset
von annotationView (Schritt 6). Ich habe den Offset von Ray Wenderlich
Schritte finden Sie in den Kommentaren über dem 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
// 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
}
Diese Lösung setzt "berechtigten" Text, hoffe nützlich zu sein:
Swift 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
}
}
Mit der öffentlichen API ist dies nicht möglich, und Sie müssen Ihre eigene benutzerdefinierte Anmerkungsansicht erneut implementieren.
Sie können sich diesen Code ansehen, der die Anmerkungsansicht neu implementiert, aber den Standard-iOS-Code nachahmt, und ihn dann an Ihre eigenen Bedürfnisse anpassen:
http://blog.asolutions.com/2010/09/building-custom-map-annotation-callouts-part-1/