Wie kann ich die Callout-Ansicht von MKAnnotationView auslösen, ohne den Pin zu berühren?

75

Ich arbeite an einem MKMapViewmit dem üblichen farbigen Stift als Standortpunkt. Ich möchte, dass das Callout angezeigt wird, ohne den Pin zu berühren.

Wie soll ich das machen Das Aufrufen setSelected:YESder Anmerkungsansicht hat nichts bewirkt. Ich denke darüber nach, eine Berührung des Stifts zu simulieren, bin mir aber nicht sicher, wie ich vorgehen soll.

Teo Choong Ping
quelle
Meine Lösung in anderer Frage: stackoverflow.com/a/13026353/736384
Luis Ascorbe

Antworten:

63

Aber es gibt einen Haken, um die Lösung von benvolioT zum Laufen zu bringen, den Code

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
    if ([currentAnnotation isEqual:annotationToSelect]) {
        [mapView selectAnnotation:currentAnnotation animated:FALSE];
    }
}

sollte von - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapViewund nirgendwo anders angerufen werden .

Die Reihenfolge, in der die verschiedenen Methoden wie viewWillAppear, viewDidAppearvon UIViewControllerund - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapViewaufgerufen werden, unterscheidet sich zwischen dem ersten Laden der Karte mit einem bestimmten Ort und dem anschließenden Anzeigen der Karte mit demselben Ort. Das ist etwas knifflig.

Steve Shi
quelle
4
Nichts kniffliges. Ich musste nur wissen, um Folgendes aufzurufen: [mapView selectAnnotation] anstelle von [annotation setSelected]. Vielen Dank!
Bentford
Okay, das hat das erste Mal automatisch funktioniert. Aber jetzt funktioniert es nicht mehr? was zum? - (void) mapViewDidFinishLoadingMap: (MKMapView *) _ mapView {[mapView selectAnnotation: addAnnotation animiert: YES]; }
Fulvio
4
mapViewDidFinishLoadingMap wird nur zum ersten Mal ausgelöst, wenn die Karten zwischengespeichert werden. Wenn die Karte aus dem Cache geladen wird, wird mapViewDidFinishloadingMap nicht mehr ausgelöst.
Niels R.
8
Die richtige Delegierungsmethode, die sicherstellt, dass Ihre Anmerkungsansicht bereit ist, das Callout anzuzeigen, ist die von @ user507778 angegebene. mapView:didAddAnnotationViews:. Dadurch wird sichergestellt, dass die Kartenansicht geladen wird und die Anmerkungsansichten platziert und bereit sind, die Callout-Blase anzuzeigen. Jede andere Möglichkeit kann funktionieren oder nicht, abhängig von der Verbindungsgeschwindigkeit, dem Cache-System, Anwendungsunterbrechungen usw.
Leandro Alves
1
@LeandroAlves Dies ist die richtige Lösung. Vielen Dank. Die Root-Antwort wurde aus demselben Grund, den Sie beschrieben haben, herabgestuft.
Aleks N.
34

Ok, hier ist die Lösung für dieses Problem.

Verwenden Sie MKMapViewdie selectAnnotation:animatedMethode, um das Callout anzuzeigen .

Teo Choong Ping
quelle
3
Das hilft nicht. Ich kann das nennen und es wird die Auswahl nicht immer animieren. Das erste Mal ja. Jedes Mal danach nein - auch wenn die Methode aufgerufen wird. Die Lösung von benvolioT funktioniert auch bei mir nicht. Auch wenn ich selectAnnotation aufrufe: animiert: direkt, wenn die Annotation bekannt ist, funktioniert es nicht. Gleiche Probleme wie zuvor. :(
Joe D'Andrea
@ Joe Ich glaube, Sie müssen die Anmerkung entfernen, bevor Sie sie abrufen, damit die Animation angezeigt wird.
Oh Danny Boy
Wenn sich der Pin im ausgewählten Zustand befindet und Sie ihn erneut auswählen, bleibt er im selben ausgewählten Zustand. bis Sie die Auswahl aufheben oder der Benutzer die Auswahl aufhebt.
dklt
32

Angenommen, Sie möchten, dass die letzte Anmerkungsansicht ausgewählt wird, können Sie den folgenden Code eingeben:

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];

im Delegierten unten:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
    //Here
    [mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];
}
user507778
quelle
Dies wäre die Lösung, die für mich funktioniert hat! vielen Dank!
Toran Billups
1
Vorsichtig! Diese Delegatmethode wird für derzeit sichtbare Anmerkungen aufgerufen, dh für Anmerkungen innerhalb des Kartenbereichs, der derzeit auf dem Bildschirm angezeigt wird.
Luis Ascorbe
21

Ok, um das Callout erfolgreich hinzuzufügen, müssen Sie selectAnnotation aufrufen: animiert, nachdem alle Annotationsansichten hinzugefügt wurden, mit den didAddAnnotationViews des Delegaten:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views{
    for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
        if ([currentAnnotation isEqual: annotationToSelect]) {
            [mapView selectAnnotation:currentAnnotation animated:YES];
        }
    }
}
Vespassassina
quelle
Ich fand, dass dies der beste Weg ist, da diese Methode beim Hinzufügen der Anmerkung ausgelöst wird.
Gavin
1
Diese Methode löscht die Beschriftung zusammen mit der PIN. Gibt es eine Lösung, die die Beschriftung direkt nach dem Ablegen der PIN auf der Karte anzeigen kann?
Michael
12

Nachdem ich verschiedene Antworten auf diesen Thread ausprobiert hatte, kam ich schließlich auf diese Idee. Es funktioniert sehr zuverlässig, ich habe noch nicht gesehen, dass es fehlschlägt:

- (void)mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views;
{
    for(id<MKAnnotation> currentAnnotation in aMapView.annotations) 
    {       
        if([currentAnnotation isEqual:annotationToSelect]) 
        {
            NSLog(@"Yay!");
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_current_queue(), ^
            {
                [aMapView selectAnnotation:currentAnnotation animated:YES];
            });
        }
    }
}

Der Block wird verwendet, um geringfügig zu verzögern, da ohne ihn das Callout möglicherweise nicht korrekt angezeigt wird.

charliehorse55
quelle
2
Nicht zu fassen. Es ist so ein Kludge und es ist in einem Rennzustand, aber es funktioniert. Was hier weht, ist, dass das Storyboard fast alles macht und es nicht offensichtlich ist, dass der Delegierte über das Storyboard verkabelt werden muss - wenn Sie MKMapViews seit 3 ​​Monaten nicht mehr berührt haben. Dies ist etwas, das das Storyboard automatisch ausführen oder zumindest warnen sollte. Ich würde lieber die mapKit-Referenz auf dem Init UND den Delegaten auf dem Init definieren, als das Storyboard die Hälfte des Jobs erledigen zu lassen und Sie hängen zu lassen, ohne zu wissen, dass noch die Hälfte des Jobs zu erledigen ist. > 1 Stunde damit verschwendet.
Alex Zavatone
Dies funktioniert hervorragend, um die Beschriftung sofort nach Abschluss des Ablegens des Pins anzuzeigen. Ohne die Verzögerung sehen Sie die Beschriftung mit dem Stift fallen, was bizarr aussieht. Es ist bedauerlich, dass "didAddAnnotationViews" in dem Moment aufgerufen wird, in dem der Pin zu fallen beginnt, nicht in dem Moment, in dem er landet.
James Toomey
9

Das funktioniert bei mir nicht. Ich vermute einen Fehler in der MapKit-API.

Unter diesem Link finden Sie Details zu anderen Personen, für die dies nicht funktioniert: http://www.iphonedevsdk.com/forum/iphone-sdk-development/19740-trigger-mkannotationview-callout-bubble.html#post110447

--bearbeiten--

Okay, nachdem ich eine Weile damit geschraubt habe, ist hier, was ich in der Lage war, Arbeit zu machen:

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
    if ([currentAnnotation isEqual:annotationToSelect]) {
        [mapView selectAnnotation:currentAnnotation animated:FALSE];
    }
}

Beachten Sie, dass hierfür eine Implementierung - (BOOL)isEqual:(id)anObjectfür Ihre Klasse erforderlich ist , die das MKAnnotation-Protokoll implementiert.

Wohlwollen
quelle
basierend darauf habe ich [mapView selectAnnotation: [mapView.annotations objectAtIndex: 0] animiert: false]; zu arbeiten, um die erste Anmerkung auszuwählen.
Andiih
6

Wenn Sie nur das Callout für die zuletzt hinzugefügte Anmerkung öffnen möchten, versuchen Sie dies, funktioniert für mich.

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];


quelle
6

Das Problem beim Aufrufen selectAnnotationvon - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapViewbesteht darin, dass dieses Ereignis, wie der Name schon sagt, erst ausgelöst wird, wenn MapView zum ersten Mal geladen wird. Sie können das Callout der Anmerkung also nicht auslösen, wenn Sie es hinzufügen, nachdem MapView vollständig geladen wurde.

Das Problem beim Aufrufen von - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)viewsist, dass Ihre Anmerkung möglicherweise nicht auf dem Bildschirm angezeigt wird, wenn sie selectAnnotationaufgerufen wird, was dazu führen würde, dass sie keine Auswirkung hat. Selbst wenn Sie die Region Ihres MapView vor dem Hinzufügen der Anmerkung auf die Koordinate der Anmerkung zentrieren, reicht die geringfügige Verzögerung zum Festlegen der Region der MapView aus selectAnnotation, um aufgerufen zu werden, bevor die Anmerkung auf dem Bildschirm angezeigt wird, insbesondere wenn Sie animieren setRegion.

Einige Leute haben dieses Problem gelöst, indem sie selectAnnotationnach einer Verzögerung als solche angerufen haben :

-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    [self performSelector:@selector(selectLastAnnotation)
        withObject:nil afterDelay:1];
}

-(void)selectLastAnnotation {
    [myMapView selectAnnotation:
        [[myMapView annotations] lastObject] animated:YES];
}

Aber selbst dann können seltsame Ergebnisse erzielt werden, da es mehr als eine Sekunde dauern kann, bis die Anmerkung auf dem Bildschirm angezeigt wird. Dies hängt von verschiedenen Faktoren ab, z. B. der Entfernung zwischen der Region Ihres vorherigen MapView und der neuen Region oder der Geschwindigkeit Ihrer Internetverbindung.

Ich habe mich - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animatedstattdessen für den Anruf entschieden, da dadurch sichergestellt wird, dass die Anmerkung tatsächlich auf dem Bildschirm angezeigt wird (vorausgesetzt, Sie setzen die Region Ihres MapView auf die Koordinate Ihrer Anmerkung), da dieses Ereignis nach Abschluss setRegion (und seiner Animation) ausgelöst wird. Allerdings wird regionDidChangeAnimatedausgelöst, wenn Ihre MapView der Region ändert, auch wenn der Benutzer schwenkt gleich um die Karte , so dass Sie sicher, müssen Sie eine Bedingung, um richtig zu identifizieren , wenn der richtige Zeitpunkt ist die Anmerkung des callout auszulösen.

So habe ich es gemacht:

MKPointAnnotation *myAnnotationWithCallout;

- (void)someMethod {
    MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
    [myAnnotation setCoordinate: someCoordinate];
    [myAnnotation setTitle: someTitle];

    MKCoordinateRegion someRegion =
       MKCoordinateRegionMakeWithDistance (someCoordinate, zoomLevel, zoomLevel);

    myAnnotationWithCallout = myAnnotation;
    [myMapView setRegion: someRegion animated: YES];
    [myMapView addAnnotation: myAnnotation];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    if (myAnnotationWithCallout)
    {
        [mapView selectAnnotation: myAnnotationWithCallout animated:YES];
        myAnnotationWithCallout = nil;
    }
}

Auf diese Weise wird Ihre Anmerkung im Moment garantiert auf dem Bildschirm angezeigt selectAnnotation des Aufrufs wird, und der if (myAnnotationWithCallout)Teil stellt sicher, dass keine andere - (void)someMethodRegionseinstellung als die in das Callout auslöst.

user1088509
quelle
5

Ich habe die API sorgfältig gelesen und schließlich das Problem gefunden:


Wenn die angegebene Anmerkung nicht auf dem Bildschirm angezeigt wird und daher keine Anmerkungsansicht zugeordnet ist, hat diese Methode keine Auswirkung.

Sie können also einige Zeit warten (z. B. 3 Sekunden) und dann diese Aktion ausführen. Dann funktioniert es.

user444974
quelle
1
Das schafft eine Rennbedingung. Gibt es nicht ein Ereignis, das anzeigt, dass die Anzeige der Karte beendet ist und mit dem Sie die Anzeige auslösen können?
Alex Zavatone
3

Aufgrund des von benvolioT angezeigten Codes, von dem ich vermute, dass er im System vorhanden ist, wurde bei Verwendung der Methode selectAnnotation: animation: der Aufruf von callOut nicht angezeigt. Der Grund dafür war vermutlich, dass er bereits ausgewählt war und vermieden wurde Bitten Sie die MapView, den CallOut auf der Karte unter Verwendung des Anmerkungstitels und des Untertitels neu zu zeichnen.

Die Lösung bestand also einfach darin, die Auswahl zuerst aufzuheben und erneut auszuwählen.

Beispiel: Zuerst musste ich dies in Apples touchMoved-Methode tun (dh wie man eine AnnotationView zieht), um callOut auszublenden. (Die einfache Verwendung von annotation.canShowAnnotation = NO allein funktioniert nicht, da ich vermute, dass es neu gezeichnet werden muss. Die AbwahlAnnotierung bewirkt die erforderliche Aktion. Auch die Abwahl allein hat diesen Trick nicht ausgeführt, der Aufruf ist nur einmal verschwunden und wurde sofort neu gezeichnet war der Hinweis, dass es automatisch wiedergewählt wurde).

annotationView.canShowAnnotation = NO;
[mapView deselectAnnotation:annotation animated:YES];

Wenn Sie dann einfach den folgenden Code in der touchEnded-Methode verwenden, wird callOut nicht zurückgebracht (Die Anmerkung wurde zu diesem Zeitpunkt vom System automatisch ausgewählt, und vermutlich tritt das Neuzeichnen des callOut nie auf):

annotationView.canShowAnnotation = YES;
[mapView selectAnnotation:annotation animated:YES];

Die Lösung war:

annotationView.canShowAnnotation = YES;
[mapView deselectAnnotation:annotation animated:YES];
[mapView selectAnnotation:annotation animated:YES];

Dadurch wurde das callOut einfach zurückgekauft, vermutlich wurde der Vorgang des erneuten Zeichnens des callOut durch die mapView erneut eingeleitet.

Genau genommen sollte ich feststellen, ob die Annotation die aktuelle Annotation ist oder nicht (ausgewählt, was ich weiß) und ob callOut tatsächlich angezeigt wird oder nicht (was ich nicht weiß), und mich dazu entschließen, sie entsprechend neu zu zeichnen sei besser. Ich habe die CallOut-Erkennungsmethode jedoch noch nicht gefunden, und es ist zu diesem Zeitpunkt nur ein wenig unnötig, dies selbst zu versuchen.

Yoichi
quelle
1

Die Antwort von Steve Shi machte mir klar, dass selectAnnotation von der mapViewDidFinishLoadingMap-Methode aufgerufen werden muss. Leider kann ich nicht abstimmen, aber ich möchte mich hier bedanken.

Gyozo Kudor
quelle
0

Fügen Sie einfach [mapView selectAnnotation: Punkt animiert: JA] hinzu;

Shamila
quelle
-1

Durch das Zurücksetzen der Anmerkungen wird auch die Beschriftung nach vorne gebracht.

    [mapView removeAnnotation: currentMarker];
    [mapView addAnnotation:currentMarker];
Zumry Mohamed
quelle