web-dev-qa-db-ja.com

MKAnnotationViewの吹き出しをカスタマイズする方法

現在、マップキットを使用していますが、行き詰っています。

使用しているカスタムアノテーションビューがあり、イメージプロパティを使用して、独自のアイコンでマップ上のポイントを表示したい。これはうまく機能しています。しかし、私がやりたいのは、デフォルトのコールアウトビュー(注釈アイコンがタッチされたときにタイトル/サブタイトルとともに表示されるバブル)をオーバーライドすることです。コールアウト自体を制御できるようにしたい:マップキットは、左右の補助コールアウトビューへのアクセスのみを提供しますが、コールアウトバブルのカスタムビューを提供したり、サイズをゼロにしたりすることはできません。

私のアイデアは、MKMapViewDelegateのselectAnnotation/deselectAnnotationをオーバーライドし、カスタムアノテーションビューを呼び出して独自のカスタムビューを描画することでした。これは機能しますが、カスタム注釈ビュークラスでcanShowCalloutYESに設定されている場合のみです。これをNOに設定している場合、これらのメソッドは呼び出されません(これは、デフォルトの吹き出しが描画されないようにするためです)。そのため、ユーザーがデフォルトの吹き出しバブルビューを表示せずに、ユーザーがマップ上のポイントに触れた(選択した)か、注釈ビューの一部ではないポイントに触れた(選択した)かどうかを知る方法がありません。

私は別の道を進んで、マップ内のすべてのタッチイベントを自分で処理しようとしましたが、これが機能していないようです。マップビューでタッチイベントをキャッチすることに関連する他の投稿を読みましたが、それはまさに私が望むものではありません。マップビューを掘り下げて、描画する前に吹き出しを削除する方法はありますか?私は迷っています。

助言がありますか?明らかな何かが欠けていますか?

88
Zach

さらに簡単な解決策があります。

カスタム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...
    }
}

ブーム、仕事は終わった。

53
TappCandy

detailCalloutAccessoryView

昔はこれは苦痛でしたが、Appleはそれを解決しました。単に MKAnnotationView のドキュメントをチェックしてください。

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

本当に、それだけです。任意のUIViewを取ります。

40

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

かなり複雑に見えますが、吹き出しのポイントが中央下になるように設計されている限り、myBubbleWidthmyBubbleHeightを自分のサイズに置き換えることができます。作業。また、サブビューのautoResizeMaskプロパティが63(つまり「すべて」)に設定されていることを忘れないでください。これにより、アニメーションで正しくスケーリングされます。

:-ジョー

13
jowie

これが私にとって最適なソリューションであることがわかりました。独自のカスタマイズを行うには、ある程度の創造性を使用する必要があります

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

subviewUICalloutViewである場合は、それをめちゃくちゃにすることができます。

同じ問題がありました。このブログには、このトピックに関する深刻なブログ投稿があります 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オブジェクトを受け取り、独自のタイトルを設定します。その後、コールアウトコンテンツの幅とサイズを調整する非常にlyい他の2つのメソッドを呼び出し、その後、適切な位置に吹き出しを描画します。

最後に、ビューがサブビューとしてmapViewに追加されます。このソリューションの問題は、マップビューがスクロールされたときに正しい位置にコールアウトを維持することが難しいことです。この問題を解決するために、領域の変更時にマップビューのデリゲートメソッドでコールアウトを非表示にしています。

これらすべての問題を解決するのに少し時間がかかりましたが、今ではコールアウトは公式のものとほとんど同じように動作しますが、私はそれを自分のスタイルで持っています。

6

基本的にこれを解決するには、次のことが必要です。a)デフォルトの吹き出しが表示されないようにします。 b)クリックされた注釈を把握します。

A)canShowCalloutをNOに設定b)サブクラス化、MKPinAnnotationView、およびtouchesBeganメソッドとtouchesEndメソッドをオーバーライドすることで、これらを達成できました。

注:MKMapViewではなくMKAnnotationViewのタッチイベントを処理する必要があります

5

私はちょうどアプローチを思いつきます、ここでのアイデアは

  // 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はサイズ320x100のUIView-showCalloutはBOOL-[self animateIn];は、UIAlertViewのようなアニメーションを表示する関数です。

3
Nikesh K

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
Fabio Napodano

コールアウトのカスタムビューを提供し、柔軟な幅/高さを非常に簡単に許可することで問題を解決する優れたSMCalloutViewのフォークをプッシュしました。まだいくつかの癖がありますが、これまでのところかなり機能的です:

https://github.com/u10int/calloutview

1
u10int