You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中Google Map点击Marker无法显示自定义Xib视图问题

解决Google Maps Marker点击不显示自定义InfoWindow的问题

我帮你排查了代码里的几个关键问题,咱们一步步来修复:

1. 修复Xib加载的错误

你的MapMarkerWindow类里的instanceFromNib方法存在问题:作为class方法,这里的self指向的是类本身而非实例,导致Xib无法正确关联IBOutlet。同时返回类型应该直接指定为MapMarkerWindow,避免后续强制转换的风险。

修改后的MapMarkerWindow代码:

class MapMarkerWindow: UIView {
    @IBOutlet weak var saloonImage: UIImageView!
    @IBOutlet weak var nameLbl: UILabel!
    @IBOutlet weak var addressLbl: UILabel!
    @IBOutlet weak var descriptionLbl: UILabel!
    
    var spotData: NSDictionary?
    
    class func instanceFromNib() -> MapMarkerWindow {
        // 这里owner传nil,因为Xib的根视图已设置为MapMarkerWindow类
        return UINib(nibName: "MapMarkerWindowView", bundle: nil).instantiate(withOwner: nil, options: nil).first as! MapMarkerWindow
    }
}

注意:要确保你的Xib文件中,根视图的Class设置为MapMarkerWindow,并且所有IBOutlet都已正确关联。

2. 给Marker绑定UserData

你在创建Marker时没有把state数据赋值给marker.userData,导致点击Marker时marker.userData为nil,后续无法给InfoWindow的控件赋值,甚至会触发崩溃。

修改创建Marker的循环代码:

for state in states {
    let state_marker = GMSMarker()
    state_marker.position = CLLocationCoordinate2D(latitude: state.lat, longitude: state.long)
    state_marker.title = state.name
    state_marker.snippet = "Hey, this is \(state.snippets)"
    
    // 把state数据转成NSDictionary绑定到userData(如果State是自定义模型,也可直接绑定模型)
    let markerData = [
        "name": state.name,
        "address": state.snippets, // 可根据你的需求替换为State的对应字段
        "description": "自定义描述内容",
        "image": UIImage(named: "saloon_default") // 替换为你的实际图片资源
    ] as NSDictionary
    state_marker.userData = markerData
    
    state_marker.map = mapView
}

3. 修复视图层级问题

你把infoWindow添加到了self.view,但之前设置了view = mapView,也就是说mapView是当前ViewController的根视图,会覆盖整个屏幕,导致infoWindow被mapView挡住。应该把infoWindow添加到mapView上:

修改didTap marker方法里的添加视图代码:

// 替换 self.view.addSubview(infoWindow) 为:
mapView.addSubview(infoWindow)

4. 修正坐标计算逻辑

mapView.projection.point(for: location)返回的是mapView坐标系内的点,所以设置infoWindow的位置时,要基于mapView的坐标系调整:

// 替换原来的位置计算代码
let markerPoint = mapView.projection.point(for: location)
var infoWindowFrame = infoWindow.frame
infoWindowFrame.origin.x = markerPoint.x - infoWindowFrame.size.width / 2
infoWindowFrame.origin.y = markerPoint.y - infoWindowFrame.size.height - 10 // 向上偏移避免挡住Marker
infoWindow.frame = infoWindowFrame

5. 优化InfoWindow的复用逻辑

你每次点击Marker都重新加载Xib创建新的infoWindow,可以改成复用已有的,避免重复创建:

在viewDidLoad里初始化一次infoWindow:

override func viewDidLoad() {
    super.viewDidLoad()
    // ...其他代码
    self.infoWindow = MapMarkerWindow.instanceFromNib()
    self.infoWindow.alpha = 0.9
    self.infoWindow.layer.cornerRadius = 12
    self.infoWindow.layer.borderWidth = 2
    // 先把infoWindow添加到mapView,初始隐藏
    self.infoWindow.isHidden = true
    mapView?.addSubview(self.infoWindow)
}

然后在didTap marker方法里只更新数据和位置:

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    guard let markerData = marker.userData as? NSDictionary else {
        infoWindow.isHidden = true
        return false
    }
    
    locationMarker = marker
    infoWindow.isHidden = false
    
    // 赋值数据
    infoWindow.nameLbl.text = markerData["name"] as? String
    infoWindow.addressLbl.text = markerData["address"] as? String
    infoWindow.descriptionLbl.text = markerData["description"] as? String
    infoWindow.saloonImage.image = markerData["image"] as? UIImage
    
    // 计算位置
    let markerPoint = mapView.projection.point(for: marker.position)
    var infoWindowFrame = infoWindow.frame
    infoWindowFrame.origin.x = markerPoint.x - infoWindowFrame.size.width / 2
    infoWindowFrame.origin.y = markerPoint.y - infoWindowFrame.size.height - 10
    infoWindow.frame = infoWindowFrame
    
    return false
}

最后,在didTapAt coordinate方法里隐藏infoWindow:

func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
    infoWindow.isHidden = true
    locationMarker = nil
}

按照这些步骤修改后,你的自定义InfoWindow应该就能正常显示了。

内容的提问来源于stack exchange,提问作者raheem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:08:09