谷歌地图的自定义信息窗口

Posted

技术标签:

【中文标题】谷歌地图的自定义信息窗口【英文标题】:Custom Info Window for Google Maps 【发布时间】:2013-05-20 18:01:49 【问题描述】:

我想为 ios 版 Google 地图制作一个自定义信息窗口,如下图所示。是否可以像 GMSMarker、GMSPolyline 和 GMSPolygon 那样扩展 GMSOverlay 来创建自定义图形?

【问题讨论】:

自定义信息窗口(== 点击窗口)或自定义标记(==始终存在)? kevinxh.github.io/swift/… 这个博客解释了如何解决这个问题。 请标记已接受的答案。 【参考方案1】:

您将需要使用markerInfoWindow 委托方法以及设置infoWindowAnchor

创建标记时,设置锚点:

GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = MARKER_POSITION;
marker.infoWindowAnchor = CGPointMake(0.44f, 0.45f);
marker.icon = [UIImage imageNamed:@"CustomMarkerImageName"];

然后创建委托方法:

- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker 
  InfoWindow *view =  [[[NSBundle mainBundle] loadNibNamed:@"InfoWindow" owner:self options:nil] objectAtIndex:0];
  view.name.text = @"Place Name";
  view.description.text = @"Place description";
  view.phone.text = @"123 456 789";
  view.placeImage.image = [UIImage imageNamed:@"customPlaceImage"];
  view.placeImage.transform = CGAffineTransformMakeRotation(-.08);
  return view;

在上面的示例中,我创建了一个 xib 然后我加载了那个xib,返回了结果UIView。相反,您可以只使用代码来构造 UIView

【讨论】:

skarE,您是否还必须制作相应的 InfoWindow 类?是否可以获得您制作的 XIB 文件的副本?谢谢! 我用这个做了一个 UIButton..但是不能点击它 你能把xib文件发给我吗? @RahulMishra 信息窗口是 UIView 的渲染版本,这就是视图无法识别用户交互的原因 信息窗口渲染在地图上如何更新数据?【参考方案2】:

对于那些试图将按钮添加到表示信息窗口的自定义视图的人 - 这似乎是不可能的,因为 Google Maps SDK 将其绘制为图像或类似的东西。但是有一个非常简单的解决方案:

    您必须创建一个自定义视图,其中包含按钮以及您需要在信息窗口中显示的任何内容。 将其作为子视图添加到您的 ma​​pView(mapView: GMSMapView, didTapMarker marker: GMSMarker) 方法中。您可以通过在 ma​​pView.projection.pointForCoordinate(marker.position) 的帮助下获取点击的标记坐标来设置自定义视图的位置

    您的自定义视图可能必须通过跟随相机位置来更改其位置,因此您必须处理 ma​​pView(mapView: GMSMapView, didChangeCameraPosition position: GMSCameraPosition) ,您可以轻松地更新自定义视图位置。

    var infoWindow = CustomInfoView()
    var activePoint : POIItem?
    
    func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool 
        if let poiItem = marker as? POIItem 
        // Remove previously opened window if any
            if activePoint != nil 
                infoWindow.removeFromSuperview()
                activePoint = nil
            
            // Load custom view from nib or create it manually
            // loadFromNib here is a custom extension of CustomInfoView
            infoWindow = CustomInfoView.loadFromNib()
            // Button is here
            infoWindow.testButton.addTarget(self, action: #selector(self.testButtonPressed), forControlEvents: .AllTouchEvents)
    
            infoWindow.center = mapView.projection.pointForCoordinate(poiItem.position)
            activePoint = poiItem
            self.view.addSubview(infoWindow)
        
        return false
    
    
    func mapView(mapView: GMSMapView, didChangeCameraPosition position: GMSCameraPosition) 
    
        if let tempPoint = activePoint 
            infoWindow.center = mapView.projection.pointForCoordinate(tempPoint.position)
        
    
    
    

【讨论】:

还会显示默认信息窗口。以及如何在指向点击标记的自定义信息上显示指示器。 @RajAggrawal 请问POIItem是什么@ @King 例如,您的包装类可能包含坐标和名称。它必须是 GMSMarker 的子类。看看here 工具提示有自己的白色背景。我可以说清楚吗?因为我已经尝试过,但似乎没有任何效果 我想它应该像您添加到 ViewController 视图中的常规子视图一样工作,但我目前无法检查。【参考方案3】:

您可以将这种类型的 UIImage 作为图标传递,如下所示

 CLLocationCoordinate2D position = CLLocationCoordinate2DMake(latitude,longitude);
 GMSMarker *location = [GMSMarker markerWithPosition:position];
 location.title = @"Location Name";
 location.icon = [UIImage imageNamed:@"marker_icon.png"];
 location.map = mapView_;

更多详情see this Documentation。

如果您在按下标记后想要这种类型的图像,那么您必须有两种类型的图像。

仅第一个图像标记图标。

第二张图片是带有地点细节的标记。

mapView 初始化时加载的标记图标,如上面的代码。

第二个图像标记和位置细节,你必须像这样在标记内部加载 delegate 方法,使用 For-LoopNSMutablearray 通过检查 marker.title 来知道哪个标记被按下。

 - (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker
 

 

【讨论】:

是的,我已经看到了,但我希望在用户触摸标记时自定义整个信息窗口。 查看更新的答案@jspooner【参考方案4】:

Swift 版本,标记自定义类的示例版本:

class CustomMarker: UIView 

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var seperator: UIImageView!
@IBOutlet weak var icon: UIImageView!
@IBOutlet weak var descriptionLabel: UILabel!

class func instanceFromNib() -> UIView 
    return UINib(nibName: "CustomMarker", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! UIView

感谢How to initialise a UIView Class with a xib file in Swift, iOS,您可以向 UIView 添加扩展,因此您不需要强制转换

protocol UIViewLoading 
extension UIView : UIViewLoading 

extension UIViewLoading where Self : UIView 

// note that this method returns an instance of type `Self`, rather than UIView
static func loadFromNib() -> Self 
    let nibName = "\(self)".characters.split$0 == ".".map(String.init).last!
    let nib = UINib(nibName: nibName, bundle: nil)
    return nib.instantiateWithOwner(self, options: nil).first as! Self


在你的委托中:

    func mapView(mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? 
    let customMarker:CustomMarker = CustomMarker.loadFromNib()
    customMarker.titleLabel.text = marker.title
    customMarker.descriptionLabel.text = marker.snippet

    return customMarker

【讨论】:

以上是关于谷歌地图的自定义信息窗口的主要内容,如果未能解决你的问题,请参考以下文章

当你从谷歌地图API中点击地图中的内置位置(不是标记)时,如何自定义弹窗的内容?

为 Android 显示自定义信息窗口 Android 地图实用程序库

带有两个可点击按钮或 ImageView 的 Google 地图 v2 自定义信息窗口

无法单击标记 - 谷歌地图集群Android,无法在谷歌地图中显示信息窗口

如何在谷歌地图上显示多个信息窗口?

显示信息窗口后阻止谷歌地图移动