Wie die Hinweisblase für MKAnnotationView anpassen?

stimmen
87

Ich arbeite zur Zeit mit dem MapKit und stecken bin.

Ich habe eine benutzerdefinierte Anmerkung Ansicht Ich verwende, und ich möchte die Bildeigenschaft verwenden, um mit meinem eigenen Symbol, um den Punkt auf der Karte angezeigt werden soll. Ich habe diese Arbeit gut. Aber was würde ich auch tun mag, ist die Standard-callout-Ansicht (die Blase, die mit dem Titel / Untertitel zeigt, wenn das Anmerkungssymbol berührt wird) außer Kraft zu setzen. Ich möchte die Legende in der Lage sein, sich selbst zu steuern: die MapKit bietet nur Zugriff auf den linken und rechten Neben callout Ansichten, aber keine Möglichkeit, eine benutzerdefinierte Ansicht für die Hinweisblase zu schaffen, oder es Null Größe zu geben, oder irgendetwas anderes.

Meine Idee war selectAnnotation / deselectAnnotation in meinem außer Kraft zu setzen MKMapViewDelegate, und dann zieht meine eigene benutzerdefinierte Ansicht , indem sie einen Anruf zu meiner benutzerdefinierten Anmerkungsansicht. Dies funktioniert, aber nur dann , wenn canShowCalloutfestgelegt ist YESin meiner benutzerdefinierten Anmerkungsansicht Klasse. Diese Methoden werden nicht genannt , wenn ich diesen Satz müssen NO(das ist , was ich will, so dass die Standard - Hinweisblase nicht gezeichnet). So habe ich keine Möglichkeit zu wissen , ob der Benutzer auf meinem Punkt auf der Karte berühren (es ausgewählt ist ) oder einen Punkt berühren , die nicht Teil meiner Beschriftungsansichten ist (delected es) , ohne die Standard - Hinweisblase View zeigen zu müssen.

Ich habe versucht, geht einen anderen Weg nach unten und Handhabung einfach alle Touch-Ereignisse selbst in der Karte, und ich kann nicht diese Arbeit zu bekommen scheinen. Ich lese andere verwandte Beiträge Touch-Ereignisse in der Kartenansicht zu fangen, aber sie sind nicht genau das, was ich will. Gibt es eine Möglichkeit in die Kartenansicht zu graben, um die Hinweisblase zu entfernen, bevor Zeichnung? Ich bin ratlos.

Irgendwelche Vorschläge? Bin ich etwas fehlt offensichtlich?

Veröffentlicht am 14/10/2009 um 13:02
quelle vom benutzer
In anderen Sprachen...                            


9 antworten

stimmen
53

Es gibt eine noch einfachere Lösung.

Erstellen Sie eine benutzerdefinierte UIView(für Ihre callout).

Dann erstellen Sie eine Unterklasse von MKAnnotationViewund Überschreibung setSelectedwie folgt:

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

Boom, Arbeit geleistet.

Beantwortet am 05/08/2011 um 12:16
quelle vom benutzer

stimmen
40

detailCalloutAccessoryView

In früheren Zeiten war dies ein Schmerz, aber Apple hat es gelöst, überprüft nur die Dokumentationen zu MKAnnotationView

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

Wirklich, das ist es. Nimmt jede UIView.

Beantwortet am 23/07/2012 um 13:44
quelle vom benutzer

stimmen
13

Anknüpfend an @ TappCandy die genial einfache Antwort, wenn Sie Ihre Blase in der gleichen Weise wie die Standard ein animieren möchten, habe ich diese Animation Verfahren hergestellt:

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

Es sieht ziemlich kompliziert, aber solange der Punkt Ihrer Hinweisblase ausgelegt ist Mitte-Boden zu sein, sollten Sie nur in der Lage sein , zu ersetzen myBubbleWidthund myBubbleHeightmit Ihrer eigenen Größe für sie zu arbeiten. Und denken Sie daran Ihre Subviews , um sicherzustellen , haben ihre autoResizeMaskEigenschaft auf 63 (dh „alle“) , so dass sie korrekt in der Animation skalieren.

: -Joe

Beantwortet am 24/10/2011 um 13:41
quelle vom benutzer

stimmen
8

Gefunden dies die beste Lösung für mich sein. Sie werden einige Kreativität nutzen, um Ihre eigenen Anpassungen zu tun

In Ihrer MKAnnotationViewUnterklasse, können Sie

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

Und wenn das subvieweine ist UICalloutView, dann kann man damit rumschraube, und was in seinem Inneren.

Beantwortet am 31/08/2011 um 21:36
quelle vom benutzer

stimmen
6

Ich hatte das gleiche Problem. Es ist eine ernste Blog - Beiträge zu diesem Thema in diesem Blog http://spitzkoff.com/craig/?p=81 .

Nur mit der MKMapViewDelegatenicht Ihnen hier und Subklassifizieren helfen MKMapViewund versuchen , die bestehenden Funktionalität erweitern auch nicht für mich arbeiten.

Was ich am Ende ist dabei meine eigenen zu schaffen , CustomCalloutViewdass ich auf meinem habe MKMapView. Sie können diese Ansicht in irgendeiner Weise Stil Sie wollen.

Mein CustomCalloutViewhat ein Verfahren ähnlich wie diese:


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

Es braucht ein MKAnnotationObjekt und setzt seine eigenen Titel, danach nennt es zwei andere Methoden , die ziemlich hässlich sind , die die Breite und Größe der callout Inhalte einstellen und danach die Sprechblase um sie an der richtigen Stelle ziehen.

Schließlich wird die Ansicht als Subview der mapView hinzugefügt. Das Problem bei dieser Lösung besteht darin, dass es schwierig ist, die Legende an der richtigen Position zu halten, wenn das Kartenansicht gescrollt wird. Ich bin nur versteckt die Legende in den Kartenansicht Delegatmethode auf einem Bereich ändern, dieses Problem zu lösen.

Es dauerte einige Zeit, um all diese Probleme zu lösen, aber jetzt ist die callout verhält sich fast wie die offiziellen, aber ich habe es in meinem eigenen Stil.

Beantwortet am 16/10/2009 um 11:35
quelle vom benutzer

stimmen
5

Im Grunde ist dies zu lösen, muss man: a) kommen die Standard-Hinweisblase verhindern. b) herauszufinden, welche Annotations geklickt wurde.

Ich war in der Lage zu erreichen diese durch: a) Methoden canShowCallout zu NO b) Subklassifizieren, MKPinAnnotationView und Überschreiben der touchesBegan und touchesEnd Einstellung.

Hinweis: Sie müssen die Berührungsereignisse für die MKAnnotationView und nicht MKMapView zu handhaben

Beantwortet am 20/11/2009 um 12:22
quelle vom benutzer

stimmen
3

Ich komme gerade mit einem Ansatz, hier ist die Idee,

  // Detect the touch point of the AnnotationView ( i mean the red or green pin )
  // Based on that draw a UIView and add it to subview.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
    CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view];
//    NSLog(@"regionWillChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y);
    [testview  setCenter:CGPointMake(newPoint.x+5,newPoint.y-((testview.frame.size.height/2)+35))];
    [testview setHidden:YES];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    CGPoint newPoint = [self.mapView convertCoordinate:selectedCoordinate toPointToView:self.view];
//    NSLog(@"regionDidChangeAnimated newPoint %f,%f",newPoint.x,newPoint.y);
    [testview  setCenter:CGPointMake(newPoint.x,newPoint.y-((testview.frame.size.height/2)+35))];
    [testview setHidden:NO];
}

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view 
{  
    NSLog(@"Select");
    showCallout = YES;
    CGPoint point = [self.mapView convertPoint:view.frame.origin fromView:view.superview];
    [testview setHidden:NO];
    [testview  setCenter:CGPointMake(point.x+5,point.y-(testview.frame.size.height/2))];
    selectedCoordinate = view.annotation.coordinate;
    [self animateIn];
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view 
{
    NSLog(@"deSelect");
    if(!showCallout)
    {
        [testview setHidden:YES];
    }
}

Hier - Testview ist eine UIViewder Größe 320x100 - showCallout BOOL ist - [self animateIn];ist die Funktion, wie Ansicht Animation tut UIAlertView.

Beantwortet am 26/01/2012 um 12:08
quelle vom benutzer

stimmen
1

Ich habe meine Gabel des ausgezeichneten SMCalloutView herausgedrückt, die mit der Bereitstellung einer benutzerdefinierten Ansicht für Beschriftungen und eine flexible Breiten / Höhen ziemlich schmerzlos das Problem löst. Immer noch zu arbeiten einige Macken, aber es ist ziemlich so weit funktional:

https://github.com/u10int/calloutview

Beantwortet am 18/10/2012 um 00:04
quelle vom benutzer

stimmen
1

Sie können leftCalloutView verwenden, das Setzen von annotation.text auf @“"

Nachfolgend finden Sie Beispielcode:

pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if(pinView == nil){
    pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];       
}
CGSize sizeText = [annotation.title sizeWithFont:[UIFont fontWithName:@"HelveticaNeue" size:12] constrainedToSize:CGSizeMake(150, CGRectGetHeight(pinView.frame))                                 lineBreakMode:UILineBreakModeTailTruncation];
pinView.canShowCallout = YES;    
UILabel *lblTitolo = [[UILabel alloc] initWithFrame:CGRectMake(2,2,150,sizeText.height)];
lblTitolo.text = [NSString stringWithString:ann.title];
lblTitolo.font = [UIFont fontWithName:@"HelveticaNeue" size:12];
lblTitolo.lineBreakMode = UILineBreakModeTailTruncation;
lblTitolo.numberOfLines = 0;
pinView.leftCalloutAccessoryView = lblTitolo;
[lblTitolo release];
annotation.title = @" ";            
Beantwortet am 14/04/2011 um 10:18
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more