MKAnnotationView के लिए कॉलआउट बुलबुले को कैसे अनुकूलित करें?


88

मैं वर्तमान में मैपकिट के साथ काम कर रहा हूं और फंस गया हूं।

मेरे पास एक कस्टम एनोटेशन दृश्य है जिसका मैं उपयोग कर रहा हूं, और मैं अपने स्वयं के आइकन के साथ मानचित्र पर बिंदु को प्रदर्शित करने के लिए छवि संपत्ति का उपयोग करना चाहता हूं। मेरे पास यह काम ठीक है। लेकिन मैं यह भी करना चाहूंगा कि डिफॉल्ट कॉलआउट दृश्य को ओवरराइड करना है (एनोटेशन आइकन को छूने पर शीर्षक / उपशीर्षक के साथ दिखाई देने वाला बुलबुला)। मैं कॉलआउट को स्वयं नियंत्रित करने में सक्षम होना चाहता हूं: मैपकिट केवल बाएं और दाएं सहायक कॉलआउट विचारों तक पहुंच प्रदान करता है, लेकिन कॉलआउट बुलबुले के लिए एक कस्टम दृश्य प्रदान करने का कोई तरीका नहीं है, या इसे शून्य आकार, या कुछ और देने के लिए।

मेरा विचार अपने में selectAnnotation / deselectAnnotation को ओवरराइड करने का था MKMapViewDelegate, और फिर मेरे कस्टम एनोटेशन दृश्य के लिए कॉल करके अपना स्वयं का कस्टम दृश्य ड्रा करें। यह काम करता है, लेकिन केवल जब मेरे कस्टम एनोटेशन व्यू क्लास में canShowCalloutसेट किया YESजाता है। इन विधियों को नहीं बुलाया जाता है अगर मेरे पास यह सेट है NO(जो कि मैं चाहता हूं, ताकि डिफ़ॉल्ट कॉलआउट बुलबुला तैयार न हो)। इसलिए मुझे यह जानने का कोई तरीका नहीं है कि क्या उपयोगकर्ता ने मानचित्र पर मेरी बात को चुना (इसे चुना) या एक बिंदु को छुआ जो कि डिफ़ॉल्ट कॉलआउट बबल व्यू शो के बिना मेरे एनोटेशन विचारों (इसे हटा दिया गया) का हिस्सा नहीं है।

मैंने एक अलग रास्ते पर जाने की कोशिश की और बस सभी स्पर्श घटनाओं को नक्शे में खुद को संभाल रहा हूं, और मुझे यह काम नहीं मिल रहा है। मैं मानचित्र दृश्य में स्पर्श घटनाओं को पकड़ने से संबंधित अन्य पोस्ट पढ़ता हूं, लेकिन वे वैसा नहीं हैं जैसा मैं चाहता हूं। क्या ड्राइंग से पहले कॉलआउट बुलबुले को हटाने के लिए मानचित्र दृश्य में खुदाई करने का एक तरीका है? मुझे हानि हो रही है।

कोई सुझाव? क्या मुझसे साफ़ - साफ़ कुछ चीज़ चूक रही है?


यह लिंक काम नहीं करता है, लेकिन यहां एक ही पोस्ट मिली -> बिल्डिंग कस्टम मैप एनोटेशन कॉलआउट - भाग 1
फेडे मिका

2
आप एक त्वरित डेमो के लिए इस परियोजना का उल्लेख कर सकते हैं । github.com/akshay1188/CustomAnnotation ऊपर चल रहे डेमो में उत्तरों का संकलन।
अक्षय

जवाबों:


53

एक और भी आसान उपाय है।

एक कस्टम बनाएँ 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...
    }
}

बूम, काम किया।


8
हाय TappCandy! सबसे पहले, आपके समाधान के लिए धन्यवाद। यह काम करता है, लेकिन जब कोई लोड लोड होता है (मैं इसे निब फ़ाइल से कर रहा हूं) बटन काम नहीं करते हैं। मैं उन्हें ठीक से काम करने के लिए क्या कर सकता हूं ?? धन्यवाद
Frade

इस समाधान की सादगी से प्यार करें!
एरिक ब्रेटो

6
हम्म - यह काम नहीं करता है! यह मैप एनोटेशन (यानी पिन) को प्रतिस्थापित करता है न कि कॉलआउट "बबल" को।
पापिल्लोनुकु

2
यह काम नहीं करेगा। MKAnnotationView में मैपव्यू का संदर्भ नहीं है, इसलिए आपके पास कस्टम कॉलआउट जोड़ने के साथ कई समस्याएं हैं। उदाहरण के लिए आप यह नहीं जानते कि इसे सबव्यू के रूप में जोड़ना ऑफस्क्रीन होगा।
कैमरन लोवेल पामर

@PapillonUK आपको कॉलआउट के फ्रेम पर नियंत्रण है। यह पिन की जगह नहीं ले रहा है, यह उसके ऊपर दिखाई दे रहा है। जब आप इसे सबव्यू के रूप में जोड़ते हैं तो इसकी स्थिति को समायोजित करें।
बेन पैकर्ड

40

detailCalloutAccessoryView

पुराने दिनों में यह एक दर्द था, लेकिन Apple ने इसे हल कर दिया है, बस MKAnnotationView पर डॉक्स की जांच करें

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

वास्तव में, यह बात है। कोई भी UIView लेता है।


कौन सा उपयोग करना सबसे अच्छा है?
सत्यम

13

@ टप्पकंडी के शानदार सरल उत्तर से जारी रखते हुए, यदि आप अपने बबल को डिफ़ॉल्ट रूप में उसी तरह से चेतन करना चाहते हैं, तो मैंने इस एनीमेशन विधि का उत्पादन किया है:

- (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 (यानी "सभी") पर सेट है ताकि वे एनीमेशन में सही पैमाने पर हों।

: -Joe


Btw, आप सामग्री की उचित स्केलिंग प्राप्त करने के लिए, फ्रेम के बजाय स्केल प्रॉपर्टी पर एनीमेशन कर सकते हैं।
क्रूस

CGRectMake का उपयोग न करें। CGTransform का उपयोग करें।
कैमरन लोवेल पामर

@occulus - मुझे लगता है कि मैंने पहले कोशिश की, लेकिन iOS 4 में मुद्दों को प्रस्तुत किया था। लेकिन ऐसा इसलिए हो सकता है क्योंकि मैं उपयोग नहीं कर रहा था CABasicAnimation... बहुत पहले याद करने के लिए! मुझे पता है कि मैं केंद्र ऑफसेट के कारण y संपत्ति को भी एनिमेट करना चाहूंगा।
jowie

@CameronLowellPalmer - क्यों नहीं उपयोग करें CGRectMake?
jowie

@jowie सिंटैक्स बेहतर है, और आपके कोड में जादू के मूल्यों से बचा जाता है। CGAffineTransformMakeScale (1.1f, 1.1f); 110% से बॉक्स बढ़ने के लिए स्पष्ट है। जिस तरह से आप इसके बारे में गए थे वह काम कर सकता है, लेकिन यह सुंदर नहीं है।
कैमरन लोवेल पामर

8

यह मेरे लिए सबसे अच्छा समाधान हो पाया। आपको अपने स्वयं के अनुकूलन करने के लिए कुछ रचनात्मकता का उपयोग करना होगा

अपने 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एक है UICalloutView, तो आप इसके साथ चारों ओर पेंच कर सकते हैं, और इसके अंदर क्या है।


1
आप कैसे चेक करते हैं कि उपविकास UICalloutView है क्योंकि UICalloutview सार्वजनिक वर्ग नहीं है।
मनीष आहूजा

if ([[[subview class] description] isEqualToString:@"UICalloutView"]) मुझे लगता है कि एक बेहतर तरीका है, लेकिन यह काम करता है।
яοвοτағτєяа '

क्या आपके पास इसके साथ कोई समस्या है क्योंकि मनीष ने बताया, यह एक निजी वर्ग है।
डैनियल

संभवतः उन्होंने कॉलआउट साक्षात्कार के लिए यूआईवाईईवाई संरचना को बदल दिया। मैंने इसका उपयोग करने वाले ऐप को अपग्रेड नहीं किया है, इसलिए आप अपने दम पर हैं: P
яοвο theағτєяа

6

मुझे भी यही समस्या थी। इस विषय पर इस ब्लॉग के बारे में एक गंभीर पोस्ट है 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ऑब्जेक्ट लेता है और अपना खुद का शीर्षक सेट करता है, बाद में यह दो अन्य तरीकों को कॉल करता है जो काफी बदसूरत होते हैं जो कॉलआउट सामग्री की चौड़ाई और आकार को समायोजित करते हैं और बाद में सही स्थिति में इसके चारों ओर भाषण बुलबुले को आकर्षित करते हैं।

अंत में दृश्य को मैप व्यू में सबव्यू के रूप में जोड़ा जाता है। इस समाधान के साथ समस्या यह है कि मानचित्र दृश्य स्क्रॉल होने पर कॉलआउट को सही स्थिति में रखना कठिन है। मैं इस समस्या को हल करने के लिए एक क्षेत्र परिवर्तन पर मैप व्यू प्रतिनिधि पद्धति में कॉलआउट छिपा रहा हूं।

उन सभी समस्याओं को हल करने के लिए कुछ समय लगा, लेकिन अब कॉलआउट लगभग एक अधिकारी की तरह व्यवहार करता है, लेकिन मेरे पास अपने स्वयं के शैली में है।


मैं दूसरा है कि: UICalloutView एक निजी वर्ग है और आधिकारिक तौर पर एसडीके में उपलब्ध नहीं है। आपका सबसे अच्छा शर्त साशा की सलाह का पालन करना है।
जोपसैक

हाय साचा, हम आपके उत्तर के लिए धन्यवाद। लेकिन, वर्तमान समस्या जो हम अनुभव कर रहे हैं, वह यह है कि पिंस दिखाई देने वाले मानचित्र पर स्थिति (x, y और अक्षांश या लंबा) कैसे प्राप्त करें, ताकि हम कॉलआउट दृश्य प्रदर्शित कर सकें।
Zach

1
परिवर्तित निर्देशांक आसानी से MKMapView के दो फ़ंक्शन द्वारा किया जा सकता है: # - ConvertCoordinate: toPointToView: # - ConvertPoint: toCoordinateFromView:
साशा

5

मूल रूप से इसे हल करने के लिए, एक की जरूरत है: क) डिफ़ॉल्ट कॉलआउट बबल को आने से रोकें। b) यह पता लगाने के लिए कि किस एनोटेशन पर क्लिक किया गया था।

मैं इन्हें प्राप्त करने में सक्षम था: क) किसी भी तरह से canShowCallout सेटिंग) उपवर्ग, MKPinAnnotationView और टचब्रेन और टचसाइड तरीकों को ओवरराइड करके।

नोट: आपको MKAnnotationView के लिए स्पर्श घटनाओं को संभालने की आवश्यकता है न कि MKMapView को


3

मैं सिर्फ एक दृष्टिकोण के साथ आता हूं, यहां विचार है

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

यहां - टेस्टव्यू 320x100 UIViewआकार का है - शोकाॅलआउट BOOL है - [self animateIn];यह फ़ंक्शन है जो एनीमेशन को पसंद करता है UIAlertView


SelectCoordinate क्या निर्दिष्ट करता है? वस्तु का प्रकार क्या है?
प्रदीप रेड्डी कीपा

यह CLLocationCoordinate2d ऑब्जेक्ट है।
भारती कुमार

1

आप 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 = @" ";            

1
यह कुछ हद तक to काम ’करेगा, लेकिन वास्तव में पूछे गए अधिक सामान्य प्रश्न का उत्तर नहीं देता है और यह बहुत हैकिश है।
कैमरन लोवेल पामर

1

मैंने उत्कृष्ट SMCalloutView के अपने कांटे को बाहर निकाल दिया है, जो कॉलआउट के लिए एक कस्टम दृश्य प्रदान करने और लचीली चौड़ाई / ऊंचाइयों को बहुत दर्द रहित रूप से अनुमति देने के साथ समस्या को हल करता है। अभी भी कुछ काम करने के लिए, लेकिन यह अभी तक बहुत कार्यात्मक है:

https://github.com/u10int/calloutview

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.