Добавить кнопки для просмотра, возвращаемые методом делегата markerInfoWindow

В настоящее время я создаю и возвращаю пользовательское представление с помощью SDK Google Maps ios, устанавливая делегата для себя и используя следующий код.

#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");
}

DidTapWindowOfMarker запускается, когда я нажимаю на пользовательское представление, но ни один из целевых методов для кнопок не запускается.

Любые идеи, почему это может быть?


person ercmcd    schedule 04.03.2013    source источник
comment
не могли бы вы опубликовать свое решение, поскольку я борюсь с той же проблемой   -  person liv a    schedule 07.08.2013


Ответы (5)


Возможно, как официально упоминается в документации Google Maps Android API, приведенное ниже ограничение в отношении infowindows относится и к Google Maps iOS SDK:

Информационное окно — это не вид в реальном времени, а вид, отображаемый в виде изображения на карте. В результате любые прослушиватели, которые вы установили для представления, игнорируются, и вы не можете различать события кликов в различных частях представления. Вам не рекомендуется размещать интерактивные компоненты, такие как кнопки, флажки или ввод текста, в пользовательское информационное окно.

Таким образом, в основном нажатие на любую часть информационного окна вызовет только "didTapWindowOfMarker"

person tony m    schedule 07.03.2013
comment
Я обнаружил, что это так, и вместо этого решил реализовать -(BOOL)mapView:(GMSMapView*)mapView didTapMarker:(id‹GMSMarker›)marker; и верните ДА; внутри этого метода так, что ответ для выбора маркера вообще не использовал информационное окно, а вместо этого использовал мое собственное решение. Спасибо за дополнительную информацию! - person ercmcd; 11.03.2013
comment
и вы перемещаете свое решение, когда карта перемещается? - person Luca Torella; 14.06.2013
comment
@ercmcd, не могли бы вы опубликовать свое решение, так как я борюсь с той же проблемой - person liv a; 07.08.2013

Решение Swift 3.0

 //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()
        }

Я добавил customInfoWindow вот так

и сделать выход этого представления (customInfoWindow) в том же контроллере, который имеет mapView.

Я получил идею по этой ссылке благодаря этому разработчику Пользовательское и интерактивное информационное окно googlemaps (IOS SDK)

person Sourabh Sharma    schedule 18.11.2016

У меня есть UView, и я добавляю делегата в представление, чтобы UIButton вызывал селектор. Для карты Google я ничего не делаю, когда звоню

- (void) mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker;

Тем не менее, я устанавливаю делегата моего информационного окна (моего пользовательского представления) на себя и вызываю все свои действия, когда нажимаю кнопку, связанную с селектором.

person kevinl    schedule 18.02.2014
comment
Привет, запускается ли действие кнопки при нажатии в любом месте пользовательского информационного окна или только при нажатии кнопки пользовательского интерфейса внутри него? Если только UIButton, то не могли бы вы вставить код. - person vkinra; 13.03.2014

ОБНОВЛЕНИЕ:

Вот код, который я использую для обнаружения нажатия на кнопки, добавленные в мой файл infoWindows. Я создаю собственное информационное окно с двумя поддельными кнопками (их можно заменить изображениями, потому что они не вызывают никаких действий) и добавляю полностью прозрачное наложение с двумя реальными кнопками поверх информационного окна. Эти кнопки будут запускать действия.

И я использую несколько методов делегата или KVC для перемещения оверлея при перемещении самого информационного окна.

- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
    [self.actionOverlayCalloutView removeFromSuperview];
    UIView *calloutView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, infoWindowWidth, infoWindowHeight)];

    float offset = anchorSize * M_SQRT2;
    CGAffineTransform rotateBy45Degrees = CGAffineTransformMakeRotation(M_PI_4);
    UIView *arrow = [[UIView alloc] initWithFrame:CGRectMake((infoWindowWidth - anchorSize)/2.0, infoWindowHeight - offset, anchorSize, anchorSize)];
    arrow.transform = rotateBy45Degrees;
    arrow.backgroundColor = [UIColor lightGrayColor];
    [calloutView addSubview:arrow];

    UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, infoWindowWidth, infoWindowHeight - offset/2)];
    [contentView setBackgroundColor:[UIColor whiteColor]];

    contentView.layer.cornerRadius = 5;
    contentView.layer.masksToBounds = YES;

    contentView.layer.borderColor = [UIColor lightGrayColor].CGColor;
    contentView.layer.borderWidth = 1.0f;

    self.actionOverlayCalloutView =
    [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:contentView]]; //hack to copy a view...
    self.actionOverlayCalloutView.backgroundColor = [UIColor lightGrayColorWithAlpha:0.5];
    self.actionOverlayCalloutView.layer.cornerRadius = 5;
    NSMutableArray *falseButtons = [NSMutableArray array];
    NSMutableArray *actionButtons = [NSMutableArray array];
    PointMapItem *pointAnnotation = marker.userData;
    if ([pointAnnotation canPerformSend]) {
        UIButton *button = [[UIButton alloc] init];
        [button setImage:[UIImage imageNamed:@"imageButton1.png"] forState:UIControlStateNormal];
        [falseButtons addObject:button];
        UIButton *activableButton = [[UIButton alloc] init];
        [activableButton addTarget:self action:@selector(onButton1Clicked) forControlEvents:UIControlEventTouchUpInside];
        [actionButtons addObject:activableButton];
    }
    if ([pointAnnotation canPerformShowDetails]) {
        UIButton *button = [[UIButton alloc] init];
        [button setImage:[UIImage imageNamed:@"imageButton1.png"] forState:UIControlStateNormal];
        [falseButtons addObject:button];
        UIButton *activableButton = [[UIButton alloc] init];
        [activableButton addTarget:self action:@selector(onButton2Clicked) forControlEvents:UIControlEventTouchUpInside];
        [actionButtons addObject:activableButton];
    }
    int buttonWidth = contentView.frame.size.width / [falseButtons count];
    int currentOffset = 0;
    for (int i=0; i<falseButtons.count; i++) {
        UIButton *falseButton = [falseButtons objectAtIndex:i];
        UIButton *activableButton = [actionButtons objectAtIndex:i];
        [falseButton setFrame:CGRectMake(currentOffset, 0, buttonWidth, contentView.frame.size.height)];
        currentOffset += buttonWidth;
        activableButton.frame = falseButton.frame;
        [activableButton setTitle:@"" forState:UIControlStateNormal];
        [self.actionOverlayCalloutView addSubview:activableButton];
        [contentView addSubview:falseButton];
    }
    [calloutView addSubview:contentView];

    CLLocationCoordinate2D anchor = [self.mapView.selectedMarker position];
    CGPoint point = [self.mapView.projection pointForCoordinate:anchor];
    point.y -= self.mapView.selectedMarker.icon.size.height + offset/2 + (infoWindowHeight - offset/2)/2;
    self.actionOverlayCalloutView.center = point;

    [self.mapView addSubview:self.actionOverlayCalloutView];
    return calloutView;
}

- (void)mapView:(GMSMapView *)pMapView didChangeCameraPosition:(GMSCameraPosition *)position {
    if (pMapView.selectedMarker != nil && self.actionOverlayCalloutView.superview) {
        CLLocationCoordinate2D anchor = [self.mapView.selectedMarker position];
        CGPoint point = [self.mapView.projection pointForCoordinate:anchor];
        float offset = anchorSize * M_SQRT2;
        point.y -= self.mapView.selectedMarker.icon.size.height + offset/2 + (infoWindowHeight - offset/2)/2;
        self.actionOverlayCalloutView.center = point;
    } else {
        [self.actionOverlayCalloutView removeFromSuperview];
    }
}

- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
    [self.actionOverlayCalloutView removeFromSuperview];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"mapView.selectedMarker"]) {
        if (!self.mapView.selectedMarker) {
            [self.actionOverlayCalloutView removeFromSuperview];
        }
    }
}

- (void)onButton2Clicked {
    //your code
    self.mapView.selectedMarker = nil;
}

- (void)onButton1Clicked {
    // your code;
    self.mapView.selectedMarker = nil;
}

ПРЕДЫДУЩЕЕ СООБЩЕНИЕ:

Взгляните на эту ветку и, в частности, на № 9, должно быть полезно https://code.google.com/p/gmaps-api-issues/issues/detail?id=4961

person Aurelien Porte    schedule 29.11.2013
comment
Хотя эта ссылка может дать ответ на вопрос, лучше включить основные части ответа здесь и указать ссылку для справки. . Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - person bummi; 29.11.2013
comment
Разве не было бы столь же эффективно и менее сложно отображать реальный пользовательский интерфейс сверху, вместо того, чтобы отделять внешний вид от действия и синхронизировать их? - person Agent Friday; 09.02.2020

1) Создайте одно подпредставление, которое вы хотите показать в информационном окне.

2) Установить рамку подвида равной рамке представления infoWindow.

  [subView setFrame:infoview.frame];
  subView =  [[[NSBundle mainBundle] loadNibNamed:@"viewName" owner:self options:nil] objectAtIndex:0];
  [self.mapview addSubview:subView];
person Dhananjay Patil    schedule 24.11.2015