1
votes

Currently, I am having an issue with my project in implementing a custom MKAnnotationView that has multiple custom UIImageViews. So these custom UIImageViews have a clear button on top of them to not have to add gesture recognizers.

enter image description here

As you can see, it would be beneficial to actually tap the MKAnnotationView subviews and have some action happen.

I implemented a protocol for the MKAnnotationView where each image subview within the MKAnnotationView makes a callback to the controller that is the owner of the MKMapView... Heres the code...

PHProfileImageView *image = [[PHProfileImageView alloc] initWithFrame:CGRectMake(newX - radius / 5.0f, newY - radius / 5.0f, width, height)];
        [image setFile:[object objectForKey:kPHEventPictureKey]];
        [image.layer setCornerRadius:image.frame.size.height/2];
        [image.layer setBorderColor:[[UIColor whiteColor] CGColor]];
        [image.layer setBorderWidth:2.0f];
        [image.layer setMasksToBounds:YES];
        [image.profileButton setTag:i];
        [image.profileButton addTarget:self action:@selector(didTapEvent:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:image];        


- (void)didTapEvent:(UIButton *)button
{
    NSLog(@"%@", [self.pins objectAtIndex:button.tag]);
    if (self.delegate && [self.delegate respondsToSelector:@selector(didTapEvent:)]) {
        [self.delegate JSClusterAnnotationView:self didTapEvent:[self.pins objectAtIndex:button.tag]];
    }
}

So as you can see, I already attempt to log the result of the tapped image but nothing :(. Is the way I'm implementing this not the way to go? Am I supposed to have CAShapeLayers or something? Not really sure at this point. Anyone got any ideas?

Edit

Im thinking that I might have to implement a custom callout view. Since a callout view actually adds buttons to its view and can respond to touch events... Not totally sure though because callouts are only shown once the annotation view is tapped. And in this case, the ACTUAL annotation view is the middle label

So I resized the mkannotationview's frame to a much larger frame and apparently all the subviews are actually not within the MKAnnotationView's bounds, so the subviews aren't actually being tapped. Now that Im thinking about this solution, it probably wasn't the best solution.

If anyone has any suggestions rather than adding subviews to a MKAnnotationView to create the view I currently have, that would be great!

1

1 Answers

3
votes

For the Custom AnnotationView with Clickable Buttons, you have to create custom AnnotationView SubClass in the Project. For that create a new file.

enter image description here

And add these two methods to the implementation file.

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* hitView = [super hitTest:point withEvent:event];
    if (hitView != nil)
    {
        [self.superview bringSubviewToFront:self];
    }
    return hitView;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
    CGRect rect = self.bounds;
    BOOL isInside = CGRectContainsPoint(rect, point);
    if(!isInside)
    {
        for (UIView *view in self.subviews)
        {
            isInside = CGRectContainsPoint(view.frame, point);
            if(isInside)
                break;
        }
    }
    return isInside;
}

Then go to the ViewController.m file again and modify the viewDidLoad method as this.

- (void)viewDidLoad {
    [super viewDidLoad];

    self.mapKit.delegate = self;

    //Set Default location to zoom
    CLLocationCoordinate2D noLocation = CLLocationCoordinate2DMake(51.900708, -2.083160); //Create the CLLocation from user cordinates
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 50000, 50000); //Set zooming level
    MKCoordinateRegion adjustedRegion = [self.mapKit regionThatFits:viewRegion]; //add location to map
    [self.mapKit setRegion:adjustedRegion animated:YES]; // create animation zooming

    // Place Annotation Point
    MKPointAnnotation *annotation1 = [[MKPointAnnotation alloc] init]; //Setting Sample location Annotation
    [annotation1 setCoordinate:CLLocationCoordinate2DMake(51.900708, -2.083160)]; //Add cordinates
    [self.mapKit addAnnotation:annotation1];
}

Now add that custom View to the ViewController.xib.

Now create this delegate method as below.

#pragma mark : MKMapKit Delegate

-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
    AnnotationView *pinView = nil; //create MKAnnotationView Property

    static NSString *defaultPinID = @"com.invasivecode.pin"; //Get the ID to change the pin
    pinView = (AnnotationView *)[self.mapKit dequeueReusableAnnotationViewWithIdentifier:defaultPinID]; //Setting custom MKAnnotationView to the ID
    if ( pinView == nil )
        pinView = [[AnnotationView alloc]
                   initWithAnnotation:annotation reuseIdentifier:defaultPinID]; // init pinView with ID

    [pinView addSubview:self.customView];
    addSubview:self.customView.center = CGPointMake(self.customView.bounds.size.width*0.1f, -self.customView.bounds.size.height*0.5f);

    pinView.image = [UIImage imageNamed:@"Pin"]; //Set the image to pinView

    return pinView;
}

I also got this answer few months ago from someone posted on Stackoverflow. I modified it to my project as I want. Hope this will do your work.