Hvordan du tilpasser bildeforklaringen boble for MKAnnotationView?

stemmer
87

Jeg jobber med mapkit og er fast.

Jeg har en tilpasset merknad utsikt jeg bruker, og jeg ønsker å bruke bildet eiendom for å vise punktet på kartet med mitt eget ikon. Jeg har denne fungerer fint. Men det jeg ønsker også å gjøre er å overstyre standardbildeforklaring view (boblen som dukker opp med tittelen / undertittel når merknaden ikonet rørt). Jeg ønsker å være i stand til å kontrollere bildeforklaringen selv: mapkit gir bare adgang til venstre og høyre hjelpe utsikt bildeforklaringen, men ingen måte å gi en tilpasset visning for callout boble, eller å gi den null størrelse, eller noe annet.

Min idé var å overstyre selectAnnotation / deselectAnnotation i min MKMapViewDelegate, og deretter trekke mitt eget syn ved å gjøre et kall til min egendefinert merknad visning. Dette fungerer, men bare når canShowCallouter satt til YESi min egendefinert merknad syn klasse. Disse metodene er ikke kalt hvis jeg har dette settet til NO(som er det jeg vil ha, slik at standard bildeforklaringen boblen ikke er tegnet). Så jeg har ingen måte å vite hvis brukeren berørt mitt poeng på kartet (valgt det) eller rørt et punkt som ikke er en del av mine merknader visninger (delected det) uten å ha standardbildeforklaring boble visning viser opp.

Jeg prøvde å gå ned en annen vei og bare håndterer alle berørings hendelser meg selv i kartet, og jeg kan ikke synes å få dette arbeidet. Jeg har lest andre innlegg relatert til fange berørings hendelser i kartvisningen, men de er ikke akkurat hva jeg vil. Er det en måte å grave i kartvisningen for å fjerne bildeforklaringen boble før tegning? Jeg er på et tap.

Noen forslag? Jeg mangler noe opplagt?

Publisert på 14/10/2009 klokken 12:02
kilden bruker
På andre språk...                            


9 svar

stemmer
53

Det er en enda enklere løsning.

Opprette en egendefinert UIView(for bildeforklaring).

Deretter oppretter du en underklasse av MKAnnotationViewog overstyring setSelectedsom følger:

- (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, jobben gjort.

Svarte 05/08/2011 kl. 11:16
kilden bruker

stemmer
40

detailCalloutAccessoryView

I gamle dager var dette en smerte, men Apple har løst det, bare sjekk docs på MKAnnotationView

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

Virkelig, det er det. Tar noen UIView.

Svarte 23/07/2012 kl. 12:44
kilden bruker

stemmer
13

Fortsetter videre fra @ TappCandy er genialt enkle svaret, hvis du ønsker å animere boble på samme måte som standard en, har jeg produsert denne animasjonsmetode:

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

Det ser ganske komplisert, men så lenge poenget med bildeforklaring boble er designet for å være midt bunnen, bør du bare være i stand til å erstatte myBubbleWidthog myBubbleHeightmed din egen størrelse for at det skal fungere. Og husk å sørge for at subviews har sin autoResizeMaskeiendom til 63 (dvs. "alle"), slik at de skalere riktig i animasjonen.

: -Joe

Svarte 24/10/2011 kl. 12:41
kilden bruker

stemmer
8

Fant dette å være den beste løsningen for meg. Du må bruke litt kreativitet for å gjøre dine egne tilpasninger

I MKAnnotationViewunderklasse, kan du bruke

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

Og hvis det subviewer en UICalloutView, så kan du skru rundt med den, og hva som er inni den.

Svarte 31/08/2011 kl. 20:36
kilden bruker

stemmer
6

Jeg hadde det samme problemet. Det er en alvorlig av blogginnlegg om dette temaet på denne bloggen http://spitzkoff.com/craig/?p=81 .

Bare ved hjelp av MKMapViewDelegateikke hjelpe deg her og subclassing MKMapViewog prøver å utvide eksisterende funksjonalitet også fungerte ikke for meg.

Det jeg endte opp med å gjøre er å lage min egen CustomCalloutViewat jeg har på toppen av min MKMapView. Du kan style denne visningen på noen måte du ønsker.

Min CustomCalloutViewhar en metode som ligner på denne:


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

Det tar et MKAnnotationobjekt og setter sin egen tittel land, siden den krever to andre metoder som er ganske stygg som justerer bredden og størrelsen av de av info innhold og derefter trekke det tale boble rundt det ved den korrekte posisjon.

Endelig utsikten er lagt til som en subview til mapView. Problemet med denne løsningen er at det er vanskelig å holde melding på riktig posisjon når kartvisningen rulles. Jeg bare gjemmer bildeforklaringen på kartet synspunkter representanten metoden på en region endring for å løse dette problemet.

Det tok litt tid å løse alle disse problemene, men nå på uthevingen oppfører seg nesten som den offisielle, men jeg har det i min egen stil.

Svarte 16/10/2009 kl. 10:35
kilden bruker

stemmer
5

Utgangspunktet for å løse dette, må man: a) Hindre standardbildeforklaring boble fra å komme opp. b) finne ut hvilken annotering ble klikket på.

Jeg var i stand til å oppnå disse ved: a) å sette canShowCallout til NO b) subclassing, MKPinAnnotationView og overstiger touchesBegan og touchesEnd metoder.

Merk: Du trenger for å håndtere berørings hendelser for MKAnnotationView og ikke MKMapView

Svarte 20/11/2009 kl. 11:22
kilden bruker

stemmer
3

Jeg bare komme opp med en tilnærming, ideen her er

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

Her - testview er en UIViewav størrelse 320x100 - showCallout er BOOL - [self animateIn];er funksjonen som gjør visningen animasjon som UIAlertView.

Svarte 26/01/2012 kl. 11:08
kilden bruker

stemmer
1

Jeg har skjøvet ut min gaffel av utmerket SMCalloutView som løser problemet med å gi en tilpasset visning for forklaringer og tillater fleksible bredder / høyder ganske smertefritt. Fortsatt noen quirks å trene, men det er ganske funksjonell så langt:

https://github.com/u10int/calloutview

Svarte 17/10/2012 kl. 23:04
kilden bruker

stemmer
1

Du kan bruke leftCalloutView, sette annotation.text til @""

Nedenfor finner du et eksempel kode:

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 = @" ";            
Svarte 14/04/2011 kl. 09:18
kilden bruker

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