現在、マップキットを使用していますが、行き詰っています。
使用しているカスタムアノテーションビューがあり、イメージプロパティを使用して、独自のアイコンでマップ上のポイントを表示したい。これはうまく機能しています。しかし、私がやりたいのは、デフォルトのコールアウトビュー(注釈アイコンがタッチされたときにタイトル/サブタイトルとともに表示されるバブル)をオーバーライドすることです。コールアウト自体を制御できるようにしたい:マップキットは、左右の補助コールアウトビューへのアクセスのみを提供しますが、コールアウトバブルのカスタムビューを提供したり、サイズをゼロにしたりすることはできません。
私のアイデアは、MKMapViewDelegate
のselectAnnotation/deselectAnnotationをオーバーライドし、カスタムアノテーションビューを呼び出して独自のカスタムビューを描画することでした。これは機能しますが、カスタム注釈ビュークラスでcanShowCallout
がYES
に設定されている場合のみです。これをNO
に設定している場合、これらのメソッドは呼び出されません(これは、デフォルトの吹き出しが描画されないようにするためです)。そのため、ユーザーがデフォルトの吹き出しバブルビューを表示せずに、ユーザーがマップ上のポイントに触れた(選択した)か、注釈ビューの一部ではないポイントに触れた(選択した)かどうかを知る方法がありません。
私は別の道を進んで、マップ内のすべてのタッチイベントを自分で処理しようとしましたが、これが機能していないようです。マップビューでタッチイベントをキャッチすることに関連する他の投稿を読みましたが、それはまさに私が望むものではありません。マップビューを掘り下げて、描画する前に吹き出しを削除する方法はありますか?私は迷っています。
助言がありますか?明らかな何かが欠けていますか?
さらに簡単な解決策があります。
カスタム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...
}
}
ブーム、仕事は終わった。
昔はこれは苦痛でしたが、Appleはそれを解決しました。単に MKAnnotationView のドキュメントをチェックしてください。
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "zebra"))
本当に、それだけです。任意のUIViewを取ります。
@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);
}];
}];
}];
}
かなり複雑に見えますが、吹き出しのポイントが中央下になるように設計されている限り、myBubbleWidth
とmyBubbleHeight
を自分のサイズに置き換えることができます。作業。また、サブビューのautoResizeMask
プロパティが63(つまり「すべて」)に設定されていることを忘れないでください。これにより、アニメーションで正しくスケーリングされます。
:-ジョー
これが私にとって最適なソリューションであることがわかりました。独自のカスタマイズを行うには、ある程度の創造性を使用する必要があります
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
である場合は、それをめちゃくちゃにすることができます。
同じ問題がありました。このブログには、このトピックに関する深刻なブログ投稿があります 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に追加されます。このソリューションの問題は、マップビューがスクロールされたときに正しい位置にコールアウトを維持することが難しいことです。この問題を解決するために、領域の変更時にマップビューのデリゲートメソッドでコールアウトを非表示にしています。
これらすべての問題を解決するのに少し時間がかかりましたが、今ではコールアウトは公式のものとほとんど同じように動作しますが、私はそれを自分のスタイルで持っています。
基本的にこれを解決するには、次のことが必要です。a)デフォルトの吹き出しが表示されないようにします。 b)クリックされた注釈を把握します。
A)canShowCalloutをNOに設定b)サブクラス化、MKPinAnnotationView、およびtouchesBeganメソッドとtouchesEndメソッドをオーバーライドすることで、これらを達成できました。
注:MKMapViewではなくMKAnnotationViewのタッチイベントを処理する必要があります
私はちょうどアプローチを思いつきます、ここでのアイデアは
// 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
のようなアニメーションを表示する関数です。
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 = @" ";
コールアウトのカスタムビューを提供し、柔軟な幅/高さを非常に簡単に許可することで問題を解決する優れたSMCalloutViewのフォークをプッシュしました。まだいくつかの癖がありますが、これまでのところかなり機能的です: