¿Cómo personalizar la burbuja de leyenda para MKAnnotationView?

votos
87

Actualmente estoy trabajando con el kit de mapas y estoy atascado.

Tengo una vista de anotación personalizada que estoy usando, y quiero usar la propiedad de la imagen para mostrar el punto en el mapa con mi propio ícono. Tengo esto funcionando bien. Pero lo que también me gustaría hacer es anular la vista de llamada predeterminada (la burbuja que aparece con el título / subtítulo cuando se toca el icono de la anotación). Deseo poder controlar la llamada en sí: el mapa solo proporciona acceso a las vistas de leyenda auxiliar izquierda y derecha, pero no es posible proporcionar una vista personalizada para la burbuja de leyenda, ni darle tamaño cero, ni ninguna otra cosa.

Mi idea era anular selectAnnotation / deselectAnnotation en my MKMapViewDelegate, y luego dibujar mi propia vista personalizada haciendo una llamada a mi vista de anotación personalizada. Esto funciona, pero solo cuando canShowCalloutestá configurado YESen mi clase de vista de anotación personalizada. Estos métodos NO se invocan si configuro esto NO(que es lo que quiero, de modo que no se dibuja la burbuja de llamada predeterminada). Por lo tanto, no tengo forma de saber si el usuario tocó mi punto en el mapa (lo seleccionó) o tocó un punto que no es parte de mis vistas de anotación (lo eliminó) sin que aparezca la vista de burbuja de llamada predeterminada.

Intenté seguir un camino diferente y simplemente manejar todos los eventos táctiles en el mapa, y parece que no puedo hacer que esto funcione. He leído otras publicaciones relacionadas con la captura de eventos táctiles en la vista del mapa, pero no son exactamente lo que quiero. ¿Hay alguna manera de profundizar en la vista de mapa para eliminar la burbuja de llamada antes de dibujar? Estoy perdido

¿Alguna sugerencia? ¿Me estoy perdiendo algo obvio?

Publicado el 14/10/2009 a las 13:02
fuente por usuario
En otros idiomas...                            


9 respuestas

votos
53

No es una solución aún más fácil.

Crear una costumbre UIView(para su leyenda).

A continuación, crear una subclase de MKAnnotationViewy anulación setSelectedde la siguiente manera:

- (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, trabajo hecho.

Respondida el 05/08/2011 a las 12:16
fuente por usuario

votos
40

detailCalloutAccessoryView

En otros tiempos, esta era un dolor, pero Apple lo ha resuelto, sólo echa la documentación sobre MKAnnotationView

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

En realidad, eso es todo. Toma cualquier UIView.

Respondida el 23/07/2012 a las 13:44
fuente por usuario

votos
13

Continuando desde @ respuesta brillante y simple de TappCandy, si se desea animar su burbuja de la misma manera que el que viene por defecto, he producido este método de animación:

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

Se ve bastante complicado, pero siempre y cuando el punto de su burbuja de llamada está diseñado para ser centro de fondo, sólo debe ser capaz de reemplazar myBubbleWidthy myBubbleHeightcon su propio tamaño para que funcione. Y recuerda que para asegurarse de que sus subvistas tienen su autoResizeMaskpropiedad establecida en 63 (es decir, "todos") a fin de que la escala correctamente en la animación.

: -Joe

Respondida el 24/10/2011 a las 13:41
fuente por usuario

votos
8

Encontrado que esto es la mejor solución para mí. Vas a tener que utilizar un poco de creatividad para hacer sus propias personalizaciones

En su MKAnnotationViewsubclase, puede utilizar

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

Y si el subviewes una UICalloutView, entonces se puede atornillar un rato con él, y lo que hay en su interior.

Respondida el 31/08/2011 a las 21:36
fuente por usuario

votos
6

Yo tuve el mismo problema. Hay una serie de publicaciones de blogs sobre este tema en este blog http://spitzkoff.com/craig/?p=81 .

Solo el uso de " MKMapViewDelegateno lo ayuda" aquí y la creación de subclases MKMapViewy el intento de extender la funcionalidad existente tampoco funcionó para mí.

Lo que terminé haciendo fue crear el mío CustomCalloutViewque estoy teniendo encima de mí MKMapView. Puede diseñar esta vista de la forma que desee.

Mi CustomCalloutViewtiene un método similar a este:


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

Toma un MKAnnotationobjeto y establece su propio título, luego llama a otros dos métodos que son bastante feos, que ajustan el ancho y el tamaño del contenido del texto destacado y luego dibujan el globo de diálogo alrededor de él en la posición correcta.

Finalmente, la vista se agrega como una subvista al mapView. El problema con esta solución es que es difícil mantener la llamada en la posición correcta cuando se desplaza la vista del mapa. Solo estoy ocultando la leyenda en el método delegado de vistas de mapa en un cambio de región para resolver este problema.

Me llevó algo de tiempo resolver todos esos problemas, pero ahora el rótulo casi se comporta como el oficial, pero lo tengo en mi propio estilo.

Respondida el 16/10/2009 a las 11:35
fuente por usuario

votos
5

Básicamente para resolver esto, se necesita: a) Evitar que aparezca la burbuja de leyenda predeterminada. b) Determine en qué anotación se hizo clic.

Pude lograr esto: a) estableciendo canShowCallout en NO b) subclassing, MKPinAnnotationView y anulando los métodos touchesBegan y touches End.

Nota: Necesita manejar los eventos táctiles para MKAnnotationView y no para MKMapView

Respondida el 20/11/2009 a las 12:22
fuente por usuario

votos
3

Acabo de llegar a una aproximación, la idea aquí es

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

Aquí - testview es una UIViewde tamaño 320x100 - showCallout es BOOL - [self animateIn];es la función que hace la vista de animación como UIAlertView.

Respondida el 26/01/2012 a las 12:08
fuente por usuario

votos
1

He presionado a cabo el tenedor de la excelente SMCalloutView que resuelve el problema de proporcionar una vista personalizada de llamadas y permitiendo anchos flexibles / alturas bastante sin dolor. Aún así algunas peculiaridades que funcionan, pero es bastante funcional hasta el momento:

https://github.com/u10int/calloutview

Respondida el 18/10/2012 a las 00:04
fuente por usuario

votos
1

Puede utilizar leftCalloutView, el establecimiento de annotation.text a @""

A continuación el código de ejemplo:

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 = @" ";            
Respondida el 14/04/2011 a las 10:18
fuente por usuario

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