Я сейчас работаю с мапкитом и застрял.
У меня есть настраиваемое представление аннотаций, которое я использую, и я хочу использовать свойство изображения для отображения точки на карте с моим собственным значком. У меня это работает нормально. Но я также хотел бы переопределить представление выноски по умолчанию (всплывающее окно с заголовком / подзаголовком при прикосновении к значку аннотации). Я хочу иметь возможность управлять самой выноской: mapkit предоставляет доступ только к левому и правому вспомогательным представлениям выноски, но не имеет возможности предоставить настраиваемый вид для пузыря выноски, или дать ему нулевой размер, или что-то еще.
Моя идея заключалась в том, чтобы переопределить selectAnnotation / deselectAnnotation в моем MKMapViewDelegate
, а затем нарисовать свое собственное представление, вызвав мое настраиваемое представление аннотации. Это работает, но только тогда , когда canShowCallout
будет установлен YES
в моем пользовательском классе просмотра аннотаций. Эти методы НЕ вызываются, если у меня установлено значение NO
(это то, что я хочу, чтобы пузырь выноски по умолчанию не рисовался). Поэтому у меня нет возможности узнать, коснулся ли пользователь моей точки на карте (выбрал ее) или коснулся точки, которая не является частью моих представлений аннотаций (отклонила ее), не отображая вид пузыря выноски по умолчанию.
Я попытался пойти другим путем и просто обрабатывать все события касания на карте самостоятельно, и мне кажется, что это не работает. Я читал другие сообщения, связанные с отслеживанием событий касания на карте, но это не совсем то, что мне нужно. Есть ли способ покопаться в представлении карты, чтобы удалить пузырь выноски перед рисованием? Я в растерянности.
Какие-либо предложения? Я упускаю что-то очевидное?
Ответы:
Есть еще более простое решение.
Создайте заказ
UIView
(для вашего уточнения).Затем создайте подкласс
MKAnnotationView
и переопределитеsetSelected
следующим образом:- (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... } }
Бум, работа сделана.
источник
detailCalloutAccessoryView
Раньше это было проблемой , но Apple решила эту проблему, просто проверьте документацию на MKAnnotationView.
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) view.canShowCallout = true view.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "zebra"))
Действительно, вот и все. Принимает любой UIView.
источник
Продолжая блестяще простой ответ @ TappCandy, если вы хотите анимировать пузырь так же, как и по умолчанию, я создал этот метод анимации:
- (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); }]; }]; }]; }
Это выглядит довольно сложно, но если точка выноски спроектирована так, чтобы она располагалась по центру внизу, вы можете просто заменить
myBubbleWidth
иmyBubbleHeight
с вашим собственным размером для его работы. И не забудьте убедиться, что для ваших подвидовautoResizeMask
свойство установлено на 63 (т.е. «все»), чтобы они правильно масштабировались в анимации.:-Джо
источник
CABasicAnimation
... Слишком давно, чтобы вспомнить! Я знаю, что мне придется анимировать свойство y из-за смещения центра.CGRectMake
?Я считаю, что это лучшее решение для меня. Вам придется проявить немного творчества, чтобы сделать свои собственные настройки
В своем
MKAnnotationView
подклассе вы можете использовать- (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++; } } } }
А если
subview
это aUICalloutView
, то с ним можно поиграть, а что внутри.источник
if ([[[subview class] description] isEqualToString:@"UICalloutView"])
Думаю, есть способ получше, но он работает.У меня такая же проблема. В этом блоге http://spitzkoff.com/craig/?p=81 есть множество сообщений на эту тему .
Простое использование здесь
MKMapViewDelegate
не помогает, а создание подклассовMKMapView
и попытки расширить существующие функциональные возможности также не помогли мне.В итоге я создал свой собственный,
CustomCalloutView
который у меня есть поверх моихMKMapView
. Вы можете стилизовать это представление по своему усмотрению.У меня
CustomCalloutView
есть метод, похожий на этот:- (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]; }
Требуется
MKAnnotation
объект и устанавливает свой собственный заголовок, после чего вызывает два других довольно уродливых метода, которые регулируют ширину и размер содержимого выноски, а затем рисуют вокруг него речевой пузырь в правильном положении.Наконец, представление добавляется в качестве подвида к mapView. Проблема с этим решением заключается в том, что трудно удерживать выноску в правильном положении при прокрутке карты. Я просто скрываю выноску в методе делегата представлений карты при изменении региона, чтобы решить эту проблему.
На решение всех этих проблем ушло время, но теперь выноска ведет себя почти как официальная, но у меня она в моем стиле.
источник
В основном, чтобы решить эту проблему, необходимо: a) Не допускать появления пузыря выноски по умолчанию. б) Выясните, какая аннотация была нажата.
Я смог добиться этого: а) установив для canShowCallout значение NO; б) создав подклассы, MKPinAnnotationView и переопределив методы touchesBegan и touchesEnd.
Примечание. Вам необходимо обрабатывать события касания для MKAnnotationView, а не для MKMapView.
источник
Я просто придумал подход, идея здесь
// 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]; } }
Здесь - testview имеет
UIView
размер 320x100 - showCallout - BOOL -[self animateIn];
это функция, которая просматривает анимацию какUIAlertView
.источник
Вы можете использовать leftCalloutView, задав для annotation.text значение @ ""
Ниже приведен пример кода:
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 = @" ";
источник
Я выпустил свой форк превосходного SMCalloutView, который решает проблему, предоставляя настраиваемый вид для выносок и довольно безболезненно позволяя гибкую ширину / высоту. По-прежнему нужно проработать некоторые причуды, но пока он довольно функциональный:
https://github.com/u10int/calloutview
источник