Add buttons to view returned by markerInfoWindow delegate method

I'm currently creating and returning a custom view with the google maps ios SDK by setting delegate to self and using the following code.

#pragma mark - GMSMapViewDelegate
-(UIView*)mapView:(GMSMapView *)mapView markerInfoWindow:(id<GMSMarker>)marker {
    int popupWidth = 200;
    int contentWidth = 180;
    int contentPad = 10;
    int popupHeight = 140;
    int popupBottomPadding = 16;
    int popupContentHeight = popupHeight - popupBottomPadding;
    int buttonHeight = 30;

    UIView *outerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, popupWidth, popupHeight)];

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, popupWidth, popupContentHeight)];
    [view setBackgroundColor:[UIColor whiteColor]];

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(contentPad, 0, contentWidth, 22)];
    [titleLabel setFont:[UIFont systemFontOfSize:17.0]];
    titleLabel.text = [marker title];

    UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(contentPad, 24, contentWidth, 20)];
    [descriptionLabel setFont:[UIFont systemFontOfSize:11.0]];
    descriptionLabel.text = [marker snippet];

    [view addSubview:titleLabel];
    [view addSubview:descriptionLabel];

    UIButton *directionButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    directionButton.frame = CGRectMake(contentPad, 45, contentWidth, buttonHeight);
    [directionButton setTitle:@"Directions" forState:UIControlStateNormal];
    [directionButton addTarget:self action:@selector(directionsPressed) forControlEvents:UIControlEventTouchDown];

    UIButton *viewLocationButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [viewLocationButton addTarget:self action:@selector(viewLocationPressed) forControlEvents:UIControlEventTouchUpInside];
    [viewLocationButton setTitle:@"View Location" forState:UIControlStateNormal];
    viewLocationButton.frame = CGRectMake(contentPad, 80, contentWidth, buttonHeight);

    // handle bottom dealio
    UIImage *bottomImage = [UIImage imageNamed:@"map-pointer-bottom"];
    UIImageView *bottomView = [[UIImageView alloc] initWithFrame:CGRectMake((popupWidth / 2) - (bottomImage.size.width / 2), (popupContentHeight), bottomImage.size.width, bottomImage.size.height)];
    [bottomView setImage:bottomImage];

    [outerView addSubview:view];
    [outerView addSubview:bottomView];
    [outerView addSubview:directionButton];
    [outerView addSubview:viewLocationButton];

    ListItem *li = (ListItem*)[marker userData];
    self.currentItem = li;
    NSLog(@"List Item %@ - %@", li.type, li.typeid);

    return outerView;
}

-(void)directionsPressed {
    NSLog(@"Directions Pressed");
}

-(void)viewLocationPressed {
    NSLog(@"Location View Pressed");
}

- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(id<GMSMarker>)marker {
    NSLog(@"Tap Captured");
}

The didTapWindowOfMarker is being fired when i tap the custom view, but neither of the target methods for the buttons are being fired.

Any ideas for why this might be?


Solution 1:

Possibly, as mentioned officially in documentation of Google Maps Android API, the below restriction regarding infowindows applies to Google Maps iOS SDK also :

Info window is not a live View, rather the view is rendered as an image onto the map. As a result, any listeners you set on the view are disregarded and you cannot distinguish between click events on various parts of the view. You are advised not to place interactive components — such as buttons, checkboxes, or text inputs — within your custom info window.

So basically clicking on any part of the infowindow will trigger only "didTapWindowOfMarker"

Solution 2:

Swift 3.0 Solution

 //empty the default infowindow
        func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
            return UIView()
        }

        // reset custom infowindow whenever marker is tapped
        func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

            customInfoView.removeFromSuperview()
        //    customInfoView.button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
            self.view.addSubview(customInfoView)

            // Remember to return false
            // so marker event is still handled by delegate
            return false
        }

        // let the custom infowindow follows the camera
        func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
            if (locationMarker != nil){
                let location = locationMarker.position
                customInfoView.center = mapView.projection.point(for: location)
            }
        }

        // take care of the close event
        func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
            customInfoView.removeFromSuperview()
        }

I have added customInfoWindow like this

and make outlet of this view(customInfoWindow) in same controller which has mapView.

I got the idea from this link thanks to this developer Custom and interactive googlemaps(IOS SDK) infowindow