Comment personnaliser la bulle pour MKAnnotationView callout?

voix
87

Je travaille actuellement avec le MapKit et je suis coincé.

J'ai une vue d'annotation personnalisée J'utilise, et je veux utiliser la propriété d'image pour afficher le point sur la carte avec mon propre icône. J'ai ce beau travail. Mais ce que je voudrais aussi faire est de passer outre la vue par défaut callout (la bulle qui apparaît avec le titre / sous-titre lorsque l'icône d'annotation est touché). Je veux être en mesure de contrôler la légende elle-même: le MapKit ne donne accès à la gauche et des vues à droite de callout auxiliaires, mais aucun moyen de fournir une vue personnalisée pour la bulle callout, ou pour lui donner la taille zéro, ou quoi que ce soit d'autre.

Mon idée était de passer outre selectAnnotation / deselectAnnotation dans mon MKMapViewDelegate, puis dessiner ma propre vue personnalisée en faisant un appel à mon avis d'annotation personnalisée. Cela fonctionne, mais seulement quand canShowCalloutest réglé sur YESmon annotation personnalisée classe d'affichage. Ces méthodes ne sont pas appelés si j'ai cet ensemble àNO (qui est ce que je veux, de sorte que la bulle par défaut est callout pas dessinée). J'ai donc aucun moyen de savoir si l'utilisateur a touché mon point sur la carte ( demandée ) ou touché un point qui ne fait pas partie de mon point de vue d'annotation (delected) sans avoir la vue de la bulle callout par défaut apparaître.

J'ai essayé d'aller sur un chemin différent et la manipulation juste tous les événements me toucher sur la carte, et je ne peux pas sembler obtenir ce travail. J'ai lu d'autres commentaires à attraper les événements tactiles dans la vue de la carte, mais ils ne sont pas exactement ce que je veux. Est-il un moyen de creuser dans la vue de la carte pour enlever la bulle avant de tirer callout? Je suis à perte.

Aucune suggestion? Est-ce que je manque quelque chose évidente?

Créé 14/10/2009 à 13:02
source utilisateur
Dans d'autres langues...                            


9 réponses

voix
53

Il existe une solution encore plus facile.

Créer une coutume UIView(pour votre callout).

Ensuite , créez une sous - classe MKAnnotationViewet override setSelectedcomme suit:

- (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, fait l'emploi.

Créé 05/08/2011 à 12:16
source utilisateur

voix
40

detailCalloutAccessoryView

Dans les temps anciens jours était une douleur, mais Apple a résolu, il suffit de cocher la documentation sur MKAnnotationView

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

Vraiment, c'est ça. Prend tout UIView.

Créé 23/07/2012 à 13:44
source utilisateur

voix
13

Dans la continuité de @ réponse brillamment simple de TappCandy, si vous voulez animer votre bulle de la même manière que celui par défaut, j'ai produit cette méthode d'animation:

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

Il semble assez compliqué, mais aussi longtemps que le point de votre bulle est conçue pour callout être centre-bas, vous devriez juste être en mesure de remplacer myBubbleWidthet myBubbleHeightavec votre propre taille pour que cela fonctionne. Et rappelez - vous pour vous assurer que vos subviews ont leur autoResizeMaskpropriété située à 63 (c. -à « tous ») de sorte qu'ils échelle correctement dans l'animation.

: -Joe

Créé 24/10/2011 à 13:41
source utilisateur

voix
8

Nous avons trouvé ce pour être la meilleure solution pour moi. Vous devrez utiliser un peu de créativité pour faire vos propres personnalisations

Dans votre MKAnnotationViewsous - classe, vous pouvez utiliser

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

Et si l' subviewest un UICalloutView, alors vous pouvez visser avec elle et ce qui est à l' intérieur.

Créé 31/08/2011 à 21:36
source utilisateur

voix
6

J'ai eu le même problème. Il y a un sérieux messages de blog sur ce sujet sur ce blog http://spitzkoff.com/craig/?p=81 .

Juste en utilisant le MKMapViewDelegatene vous aide pas ici et subclassing MKMapViewet d' essayer d'étendre les fonctionnalités existantes ne fonctionne pas non plus pour moi.

Ce que je fini par faire est de créer mon propre CustomCalloutViewque j'ai sur ma MKMapView. Vous pouvez définir le style de ce point de vue comme vous le souhaitez.

Ma CustomCalloutViewa une méthode similaire à celle - ci:


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

Il prend un MKAnnotationobjet et définit son propre titre, par la suite , il appelle deux autres méthodes qui sont assez laids qui ajustent la largeur et la taille du contenu de légende et d'en tirer ensuite la bulle autour de lui à la bonne position.

Enfin, la vue est ajouté en tant que sous-vue à la Mapview. Le problème avec cette solution est qu'il est difficile de garder la légende à la bonne position lorsque la vue de la carte est défilée. Je suis juste cacher la légende dans les vues de la carte méthode déléguée sur un changement de région pour résoudre ce problème.

Il a fallu un certain temps pour résoudre tous ces problèmes, mais maintenant la presque comme se comporte callout l'officiel, mais je l'ai dans mon propre style.

Créé 16/10/2009 à 11:35
source utilisateur

voix
5

Fondamentalement, pour résoudre ce problème, il faut: a) Prévenir la bulle par défaut de callout à venir. b) la figure sur laquelle l'annotation a été cliqué.

J'ai pu atteindre ces par: a) la mise en canShowCallout NO b) subclassing, MKPinAnnotationView et en remplaçant les méthodes touchesBegan et touchesEnd.

Remarque: vous devez gérer les événements tactiles pour la MKAnnotationView et non MKMapView

Créé 20/11/2009 à 12:22
source utilisateur

voix
3

Je viens juste avec une approche, l'idée est ici

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

Ici - testview est UIViewde taille 320x100 - showCallout est BOOL - [self animateIn];est la fonction qui fait l' animation de vue comme UIAlertView.

Créé 26/01/2012 à 12:08
source utilisateur

voix
1

Je l'ai poussé ma fourchette de l'excellent SMCalloutView qui résout le problème de fournir une vue personnalisée pour permettre et assez accroches largeurs / hauteurs sans douleur flexibles. Encore quelques bizarreries de travailler, mais il est assez fonctionnel jusqu'à présent:

https://github.com/u10int/calloutview

Créé 18/10/2012 à 00:04
source utilisateur

voix
1

Vous pouvez utiliser leftCalloutView, la mise à annotation.text @ »"

S'il vous plaît trouverez ci-dessous le code exemple:

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 = @" ";            
Créé 14/04/2011 à 10:18
source utilisateur

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