2011-12-12 73 views
2

如何檢測註釋標註的標題的點擊?我已經有了一個正確的標註配件和一個左側標籤,但是我想要檢測用戶是否點擊標題(位於標註的中心)。檢測標註的標註

如果這是不可能的,如果我點擊標題,如何禁用隱藏標註?

回答

4

回答你的問題有點晚,但我最近處理的是同樣的問題,並通過我自己的試驗和錯誤來解決我的問題。也許我可以幫助處理同樣問題的人。

你也可以使用一些自定義註釋和標註視圖類,這裏有很多例子。 但是,還有一種簡單的方法可以在不使用複雜的外部類的情況下解決這個問題。

問題定義: 我希望能夠通過觸摸標註視圖來觸發某些方法。 我不想使用右側或左側的配件按鈕。 但是當我觸摸標註視圖時,視圖將立即消失。

解決方案的簡短說明: 只需使用自定義的「MKPinAnnotationView」和「hittest」來檢測標註視圖中的觸摸。

你也可以在帖子末尾找到github項目鏈接。

touchableCallOutsViewController.h

// 
// touchableCallOutsViewController.h 
// touchableCallOuts 
// 
// Created by yasin turkoglu on 20.11.2012. 
// Copyright (c) 2012 yasin turkoglu. All rights reserved. 
// 

#import <UIKit/UIKit.h> 
#import <MapKit/MapKit.h> 


@class myCustomPinAnnotationClass; 

@interface touchableCallOutsViewController : UIViewController <MKMapViewDelegate> { 
    MKMapView *myMapView; 
    int pinCounter; 
    myCustomPinAnnotationClass *myAnnotation; 
    CLLocationCoordinate2D selectedPinCoordinate; 
    int selectedPinNumber; 
} 

@property (strong, nonatomic) MKMapView *myMapView; 
@property (strong, nonatomic) myCustomPinAnnotationClass *myAnnotation; 
@end 

touchableCallOutsViewController.m

// 
// touchableCallOutsViewController.m 
// touchableCallOuts 
// 
// Created by yasin turkoglu on 20.11.2012. 
// Copyright (c) 2012 yasin turkoglu. All rights reserved. 
// 

#import "touchableCallOutsViewController.h" 
#import "myCustomPinAnnotationClass.h" 

@interface touchableCallOutsViewController() 

@end 



@implementation touchableCallOutsViewController 

@synthesize myMapView; 
@synthesize myAnnotation; 

- (void)viewDidLoad 
{ 

    //first we create mapview and add pin annotation 

    myMapView = [[MKMapView alloc]initWithFrame:self.view.frame]; 
    myMapView.delegate = self; 
    MKCoordinateRegion region = {{0,0},{1.0,1.0}}; 
    region.center.latitude = 41.036651; //user defined 
    region.center.longitude = 28.983870;//user defined 
    [myMapView setRegion:region animated:YES]; 
    [self.view addSubview:myMapView]; 

    //we define long press recognizer for 2 seconds and add our map view to add new pin when you press 2 seconds on map view 
    UILongPressGestureRecognizer *lngPrs = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleMyLongPress:)]; 
    lngPrs.minimumPressDuration = 2.0; 
    [myMapView addGestureRecognizer:lngPrs]; 

    pinCounter = 1; //this variable hold pin numbers and increment 1 when new pin added. 

    myAnnotation = [[myCustomPinAnnotationClass alloc]initWithName:[NSString stringWithFormat:@"Pin %i",pinCounter] description:@"touch here to see pin coordinates" pinNum:pinCounter coordinate:region.center]; 
    [myMapView addAnnotation:myAnnotation]; 

} 

- (void)handleMyLongPress:(UIGestureRecognizer *)gestureRecognizer 
{ 
    if (gestureRecognizer.state != UIGestureRecognizerStateBegan) { 

    }else{ 
     //when we press more than 2 seconds on map view UILongPressGestureRecognizer triggered this method and call our custom MKPinAnnotationView class and add annotation. 
     CGPoint touchPoint = [gestureRecognizer locationInView:myMapView]; 
     CLLocationCoordinate2D touchMapCoordinate = [myMapView convertPoint:touchPoint toCoordinateFromView:myMapView]; 
     pinCounter++; 
     myAnnotation = [[myCustomPinAnnotationClass alloc]initWithName:[NSString stringWithFormat:@"Pin %i",pinCounter] description:@"touch here to see pin coordinates" pinNum:pinCounter coordinate:touchMapCoordinate]; 
     [myMapView addAnnotation:myAnnotation]; 
    } 
} 

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation 
{ 
    //when new annotation added by us, new annotation property will set here 
    static NSString *identifier = @"myPins"; 
    if ([annotation isKindOfClass:[myCustomPinAnnotationClass class]]) { 
     myCustomPinAnnotationClass *annotationView = (myCustomPinAnnotationClass *) [self.myMapView dequeueReusableAnnotationViewWithIdentifier:identifier]; 

     if (annotationView == nil) { 
      annotationView = [[myCustomPinAnnotationClass alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; 
     } else { 
      annotationView.annotation = annotation; 
     } 

     myAnnotation = (myCustomPinAnnotationClass *)annotation; 

     annotationView.pinColor = MKPinAnnotationColorGreen;  
     annotationView.enabled = YES; 
     annotationView.draggable = YES; 
     annotationView.canShowCallout = YES; 
     [annotationView setSelected:YES animated:YES]; 
     return annotationView; 

    }  
    return nil; 

} 

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view 
{ 

    //if you select any annotation to show their callout sellected annotation pin number and coordinate setted and call findcallot method  
    myAnnotation = (myCustomPinAnnotationClass *)view.annotation; 
    selectedPinCoordinate = myAnnotation.coordinate; 
    selectedPinNumber = myAnnotation.pinNum; 
    [self findCallOut:myMapView]; 
} 


- (void)findCallOut:(UIView *)node 
{ 
    //this method dig our mapview with for loop until find callout view class named "UICalloutView" 

    if([node isKindOfClass:[NSClassFromString(@"UICalloutView") class]]){ 

     //this method trigered together with callout open animation. 

     //in UICalloutView we have callout bubble image 
     //we dig it with for loop to find this image height 
     float buubleHeight = 0.0; 
     for(UIImageView *bubbleComponents in node.subviews){ 
      //when we find callout bubble image take height to set our touchable area height 
      buubleHeight = bubbleComponents.frame.size.height; 
      break; 
     } 



     //this method triger with callout open animation as I said before 
     //ant this bouncing open animation distort actual size of callout view 
     //so when this happens we also get transform value of callout view and make proportion to find exact sizes. 
     CGFloat nodeTransformRatio = node.transform.a; 
     CGFloat calculatedWidth = roundf(node.frame.size.width/nodeTransformRatio); 
     CGFloat calculatedHeight = roundf(buubleHeight/nodeTransformRatio); 

     //now create a new UIView and sized according to callout view. 
     UIView *touchableView = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, calculatedWidth, calculatedHeight)]; 
     touchableView.userInteractionEnabled = YES; 

     //we add new single tap gesture recognizer to triger desired method when users touching to the callout 
     UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSomething)]; 
     [touchableView addGestureRecognizer:singleTap]; 
     //and finaly we add this newly created view in callout view to receive touches. 
     [node addSubview:touchableView]; 

    }else{ 
     //loop self until find a "UICalloutView" 
     for(UIView *child in node.subviews){ 
      [self findCallOut:child]; 
     } 
    } 
} 

- (void)doSomething 
{ 
    //this method call allert view our preseted variables when users touch callout view. 
    UIAlertView *alertHolder = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"You're touched the Pin %i CallOut",selectedPinNumber] message:[NSString stringWithFormat:@"lat : %f\nlong : %f",selectedPinCoordinate.latitude,selectedPinCoordinate.longitude] delegate:self cancelButtonTitle:nil otherButtonTitles:@"ok",nil]; 
    [alertHolder show]; 

} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

@end 

myCustomPinAnnotationClass.h

// 
// myCustomPinAnnotationClass.h 
// touchableCallOuts 
// 
// Created by yasin turkoglu on 20.11.2012. 
// Copyright (c) 2012 yasin turkoglu. All rights reserved. 
// 

#import <MapKit/MapKit.h> 


@interface myCustomPinAnnotationClass : MKPinAnnotationView <MKAnnotation> { 
    NSString *_name; 
    NSString *_description; 
    int _pinNum; 
    CLLocationCoordinate2D _coordinate; 
} 

@property (copy) NSString *name; 
@property (copy) NSString *description; 
@property (nonatomic, readonly) int pinNum; 
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; 

- (id)initWithName:(NSString*)header description:(NSString*)description pinNum:(int)pinNum coordinate:(CLLocationCoordinate2D)coordinate; 

@end 

myCustomPinAnnotationClass.m

// 
// myCustomPinAnnotationClass.m 
// touchableCallOuts 
// 
// Created by yasin turkoglu on 20.11.2012. 
// Copyright (c) 2012 yasin turkoglu. All rights reserved. 
// 

#import "myCustomPinAnnotationClass.h" 

@implementation myCustomPinAnnotationClass 

@synthesize name = _name; 
@synthesize description = _description; 
@synthesize pinNum = _pinNum; 
@synthesize coordinate = _coordinate; 


- (id)initWithName:(NSString*)header description:(NSString*)description pinNum:(int)pinNum coordinate:(CLLocationCoordinate2D)coordinate 
{ 
    self = [super init]; 
    if (self) { 
     _name = [header copy]; 
     _description = [description copy]; 
     _pinNum = pinNum; 
     _coordinate = coordinate; 
    } 
    return self; 
} 

- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate 
{ 
    _coordinate = newCoordinate; 
} 

- (NSString *)title { 
    return _name; 
} 

- (NSString *)subtitle { 
    return _description; 
} 

- (int)tag { 
    return _pinNum; 
} 

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event 
{ 
    //test touched point in map view 
    //when hit test return nil callout close immediately by default 
    UIView* hitView = [super hitTest:point withEvent:event]; 
    // if hittest return nil test touch point 
    if (hitView == nil){ 
     //dig view to find custom touchable view lately added by us 
     for(UIView *firstView in self.subviews){ 
      if([firstView isKindOfClass:[NSClassFromString(@"UICalloutView") class]]){ 
       for(UIView *touchableView in firstView.subviews){ 
        if([touchableView isKindOfClass:[UIView class]]){ //this is our touchable view class 
         //define touchable area 
         CGRect touchableArea = CGRectMake(firstView.frame.origin.x, firstView.frame.origin.y, touchableView.frame.size.width, touchableView.frame.size.height); 
         //test touch point if in touchable area 
         if (CGRectContainsPoint(touchableArea, point)){ 
          //if touch point is in touchable area return touchable view as a touched view 
          hitView = touchableView; 
         } 
        } 
       }     
      } 
     } 
    } 
    return hitView; 
} 

@end 

在這裏,您可以下載完整的項目源代碼https://github.com/ytur/touchableCallOutsForIOSMaps

+0

你好@ytur我有同樣的問題,我的自定義詳圖索引視圖上市。我已經實現了'hitTest:withEvent:',但'[super hitTest:withEvent:]'永遠不會返回'nil'。當我點擊標註視圖時 - 它消失了,但是當我點擊標註視圖上的按鈕時 - 它沒有。有任何想法嗎? – k06a

+0

這裏是我的完整問題:http://stackoverflow.com/questions/17449775/custom-map-callout-view-hides-on-tap – k06a