Obecnie pracuję z mapkitem i utknąłem.
Mam niestandardowy widok adnotacji, którego używam, i chcę użyć właściwości obrazu, aby wyświetlić punkt na mapie z własną ikoną. Mam to działa dobrze. Ale chciałbym również zastąpić domyślny widok objaśnienia (dymek, który pojawia się z tytułem / podtytułem po dotknięciu ikony adnotacji). Chcę mieć możliwość kontrolowania samego objaśnienia: zestaw map zapewnia dostęp tylko do lewego i prawego pomocniczego widoku objaśnień, ale nie ma możliwości zapewnienia niestandardowego widoku dla dymka objaśnienia, nadania mu zerowego rozmiaru lub czegokolwiek innego.
Mój pomysł polegał na nadpisaniu selectAnnotation / deselectAnnotation w moim MKMapViewDelegate
, a następnie narysowaniu własnego widoku niestandardowego, wywołując mój niestandardowy widok adnotacji. To działa, ale tylko wtedy, gdy canShowCallout
jest ustawione na YES
w mojej niestandardowej klasie widoku adnotacji. Te metody NIE są wywoływane, jeśli ustawię to na NO
(co jest tym, czego chcę, aby domyślny bąbelek wywołania nie był rysowany). Nie mam więc możliwości dowiedzenia się, czy użytkownik dotknął mojego punktu na mapie (zaznaczył go) lub dotknął punktu, który nie jest częścią moich widoków adnotacji (usunął go) bez wyświetlania domyślnego widoku dymka objaśnień.
Próbowałem pójść inną ścieżką i po prostu sam obsługiwać wszystkie zdarzenia dotykowe na mapie, ale nie wydaje mi się, aby to działało. Czytałem inne posty związane z łapaniem zdarzeń dotykowych w widoku mapy, ale nie są one dokładnie tym, czego chcę. Czy istnieje sposób, aby zagłębić się w widok mapy, aby usunąć dymek objaśnienia przed rysowaniem? Jestem zagubiony.
Jakieś sugestie? Czy brakuje mi czegoś oczywistego?
Odpowiedzi:
Jest jeszcze prostsze rozwiązanie.
Utwórz niestandardowy
UIView
(dla swojego objaśnienia).Następnie utwórz podklasę
MKAnnotationView
i nadpiszsetSelected
w następujący sposób:- (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... } }
Bum, praca wykonana.
źródło
detailCalloutAccessoryView
W dawnych czasach było to uciążliwe, ale Apple to rozwiązało, po prostu sprawdź dokumentację na MKAnnotationView
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) view.canShowCallout = true view.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "zebra"))
Naprawdę, to wszystko. Pobiera dowolny UIView.
źródło
Kontynuując genialnie prostą odpowiedź @ TappCandy, jeśli chcesz animować swój bąbelek w taki sam sposób, jak domyślny, stworzyłem tę metodę animacji:
- (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); }]; }]; }]; }
Wygląda to na dość skomplikowane, ale tak długo, jak punkt Twojego dymka objaśnienia jest zaprojektowany tak, aby znajdował się pośrodku dołu, powinieneś mieć możliwość wymiany
myBubbleWidth
imyBubbleHeight
własnego rozmiaru, aby działał. I pamiętaj, aby upewnić się, że podglądy mają swojąautoResizeMask
właściwość ustawioną na 63 (tj. „Wszystkie”), aby były prawidłowo skalowane w animacji.: -Joe
źródło
CABasicAnimation
... Zbyt dawno temu, żeby pamiętać! Wiem, że musiałbym również animować właściwość y ze względu na przesunięcie środka.CGRectMake
?Okazało się, że jest to dla mnie najlepsze rozwiązanie. Będziesz musiał wykazać się kreatywnością, aby dokonać własnych dostosowań
W swojej
MKAnnotationView
podklasie możesz użyć- (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++; } } } }
A jeśli
subview
jest aUICalloutView
, to możesz się z tym pieprzyć i co jest w środku.źródło
if ([[[subview class] description] isEqualToString:@"UICalloutView"])
Myślę, że jest lepszy sposób, ale to działa.Miałem ten sam problem. Na tym blogu http://spitzkoff.com/craig/?p=81 znajduje się wiele postów na ten temat .
Samo użycie
MKMapViewDelegate
nie pomoże ci tutaj, a tworzenie podklasMKMapView
i próba rozszerzenia istniejącej funkcjonalności również nie działa dla mnie.Skończyło się na stworzeniu własnego,
CustomCalloutView
który mam nad sobąMKMapView
. Możesz stylizować ten widok w dowolny sposób.My
CustomCalloutView
ma metodę podobną do tej:- (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]; }
Pobiera
MKAnnotation
obiekt i ustawia własny tytuł, a następnie wywołuje dwie inne metody, które są dość brzydkie, które dostosowują szerokość i rozmiar zawartości objaśnienia, a następnie rysują wokół niego dymek mowy we właściwej pozycji.Na koniec widok jest dodawany jako widok podrzędny do mapView. Problem z tym rozwiązaniem polega na tym, że trudno jest utrzymać objaśnienie we właściwej pozycji podczas przewijania widoku mapy. Właśnie ukrywam objaśnienie w metodzie delegowania widoków mapy na zmianę regionu, aby rozwiązać ten problem.
Zajęło trochę czasu, aby rozwiązać wszystkie te problemy, ale teraz objaśnienie zachowuje się prawie jak oficjalne, ale mam je w swoim własnym stylu.
źródło
Zasadniczo, aby rozwiązać ten problem, należy: a) zapobiec wyświetlaniu domyślnego dymka objaśnienia. b) Dowiedz się, która adnotacja została kliknięta.
Udało mi się to osiągnąć poprzez: a) ustawienie canShowCallout na NO b) podklasę, MKPinAnnotationView i nadpisanie metod touchesBegan i touchesEnd.
Uwaga: musisz obsłużyć zdarzenia dotyku dla MKAnnotationView, a nie MKMapView
źródło
Po prostu wymyśliłem podejście, chodzi o to
// 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]; } }
Tutaj - testview ma
UIView
rozmiar 320x100 - showCallout to BOOL -[self animateIn];
to funkcja, która wyświetla animację jakUIAlertView
.źródło
Możesz użyć leftCalloutView, ustawiając adnotation.text na @ ""
Poniżej przykładowy kod:
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 = @" ";
źródło
Wypchnąłem widelec doskonałego SMCalloutView, który rozwiązuje problem z zapewnieniem niestandardowego widoku objaśnień i umożliwianiem elastycznych szerokości / wysokości dość bezboleśnie. Wciąż jest kilka dziwactw do rozwiązania, ale jak dotąd jest całkiem funkcjonalny:
https://github.com/u10int/calloutview
źródło