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

如何实现Google Maps中点击集群图标切换图标

解决Google Maps集群图标点击切换问题

我明白你的问题:单个标记点击能切换图标,但集群图标点击后毫无反应。核心原因是你没有跟踪集群标记的选中状态,也没有在点击时更新集群图标的逻辑。下面是一步步的解决方案:

1. 扩展CustomMarker以支持集群选中状态

首先,确保你的CustomMarker能记录集群的选中状态,复用现有的isSelected属性即可(通过markerType区分是单个标记还是集群):

class CustomMarker: GMSMarker {
    enum MarkerType {
        case clusterType
        case itemType
    }
    
    var markerType: MarkerType = .itemType
    var markerCount: Int = 0
    var propertyListModal: PeropertyListModel?
    var isSelected: Bool = false // 单个标记和集群共用这个状态
}

2. 修改ClusterIconGenerator支持选中状态的图标生成

让图标生成器能根据选中状态返回不同的基础图片(比如选中时用clusterMarkerSelected,未选中用clusterMarker):

class ClusterIconGenerator: GMUDefaultClusterIconGenerator {
    // 新增方法:根据选中状态生成图标
    func icon(forSize size: UInt, isSelected: Bool) -> UIImage {
        let baseImageName = isSelected ? "clusterMarkerSelected" : "clusterMarker"
        guard let baseImage = UIImage(named: baseImageName) else {
            return super.icon(forSize: size) //  fallback到默认逻辑
        }
        return textToImage(drawText: String(size) as NSString, inImage: baseImage, font: UIFont(name: "Futura-Medium", size: 12.0) ?? UIFont.systemFont(ofSize: 12))
    }
    
    // 保留原有方法供默认调用
    override func icon(forSize size: UInt) -> UIImage {
        return icon(forSize: size, isSelected: false)
    }
    
    // 原有textToImage方法不变
    private func textToImage(drawText text: NSString, inImage image: UIImage, font: UIFont) -> UIImage {
        UIGraphicsBeginImageContext(image.size)
        image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
        let textStyle = NSMutableParagraphStyle()
        textStyle.alignment = NSTextAlignment.center
        let textColor = UIColor.black
        let attributes=[
            NSAttributedString.Key.font: font,
            NSAttributedString.Key.paragraphStyle: textStyle,
            NSAttributedString.Key.foregroundColor: textColor]
        let textH = font.lineHeight
        let textY = (image.size.height-textH)/2
        let textRect = CGRect(x: 0, y: textY, width: image.size.width, height: textH)
        text.draw(in: textRect.integral, withAttributes: attributes)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result!
    }
}

3. 在ViewController中跟踪选中的集群标记

添加一个变量来记录当前选中的集群标记,方便后续重置状态:

class SearchViewController: UIViewController {
    private var selectedClusterMarker: CustomMarker?
    // 你的其他现有变量...
}

4. 更新Renderer代理方法处理集群图标

修改renderer(_:markerFor:)初始化集群标记的状态,同时在renderer(_:didRenderMarker:)中根据选中状态生成集群图标:

func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
    let marker = CustomMarker()
    if let itemMarker = object as? GMUCluster {
        marker.markerType = .clusterType
        marker.markerCount = itemMarker.items.count
        // 初始化选中状态:如果是之前选中的集群,设置为true
        marker.isSelected = (selectedClusterMarker?.markerCount == itemMarker.items.count && selectedClusterMarker?.position == itemMarker.position)
    } else if let itemMarker = object as? POIItem {
        marker.markerType = .itemType
        itemMarker.marker = marker
        marker.propertyListModal = itemMarker.propertyListModal
        marker.isSelected = false
    }
    return marker
}

func renderer(_ renderer: GMUClusterRenderer, didRenderMarker marker: GMSMarker) {
    if let customMarker = marker as? CustomMarker {
        if customMarker.markerType == .itemType {
            // 原有单个标记的处理逻辑不变
            let propertyMarker = createMarkerView(isSelected: customMarker.isSelected)
            propertyMarker.markerPriceLabel.text = customMarker.propertyListModal?.propertyPrice
            marker.icon = propertyMarker.asImage()
            marker.groundAnchor = CGPoint(x: 0.5, y: 1)
        } else if customMarker.markerType == .clusterType {
            // 新增集群图标渲染逻辑
            let iconGenerator = ClusterIconGenerator()
            let clusterIcon = iconGenerator.icon(forSize: UInt(customMarker.markerCount), isSelected: customMarker.isSelected)
            marker.icon = clusterIcon
            marker.groundAnchor = CGPoint(x: 0.5, y: 0.5) // 集群图标通常居中显示
        }
    }
}

5. 修改集群点击代理方法,实现图标切换

在clusterManager(_:didTap:)中,处理集群点击时的状态切换和图标更新:

func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
    // 1. 重置之前选中的集群状态
    if let previousClusterMarker = selectedClusterMarker {
        previousClusterMarker.isSelected = false
        let iconGenerator = ClusterIconGenerator()
        let clusterIcon = iconGenerator.icon(forSize: UInt(previousClusterMarker.markerCount), isSelected: false)
        previousClusterMarker.icon = clusterIcon
    }
    
    // 2. 获取当前点击的集群对应的Marker
    let renderer = clusterManager.renderer as! GMUDefaultClusterRenderer
    guard let currentClusterMarker = renderer.marker(for: cluster) as? CustomMarker else {
        // 执行原有逻辑(如果没找到标记)
        let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: propertyMapView.camera.zoom)
        propertyMapView.moveCamera(GMSCameraUpdate.setCamera(newCamera))
        isClusterTapped = true
        clusterPropertyList = cluster.items.compactMap { ($0 as? POIItem)?.propertyListModal }
        self.propertyMapView.selectedMarker = nil
        self.propertyListContainerForMap.isHidden = false
        self.propertyViewForMapCollectionView.reloadData()
        return true
    }
    
    // 3. 切换当前集群的选中状态并更新图标
    currentClusterMarker.isSelected = !currentClusterMarker.isSelected
    let iconGenerator = ClusterIconGenerator()
    let clusterIcon = iconGenerator.icon(forSize: UInt(currentClusterMarker.markerCount), isSelected: currentClusterMarker.isSelected)
    currentClusterMarker.icon = clusterIcon
    
    // 4. 更新选中集群的记录
    selectedClusterMarker = currentClusterMarker.isSelected ? currentClusterMarker : nil
    
    // 5. 执行原有业务逻辑
    let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: propertyMapView.camera.zoom)
    propertyMapView.moveCamera(GMSCameraUpdate.setCamera(newCamera))
    isClusterTapped = true
    clusterPropertyList = cluster.items.compactMap { ($0 as? POIItem)?.propertyListModal }
    self.propertyMapView.selectedMarker = nil
    self.propertyListContainerForMap.isHidden = false
    self.propertyViewForMapCollectionView.reloadData()
    
    return true
}

6. 点击单个标记时重置集群选中状态

在单个标记的点击代理方法中,添加重置集群选中状态的逻辑,避免状态冲突:

func clusterManager(_ clusterManager: GMUClusterManager, didTap clusterItem: GMUClusterItem) -> Bool {
    // 重置选中的集群
    if let previousClusterMarker = selectedClusterMarker {
        previousClusterMarker.isSelected = false
        let iconGenerator = ClusterIconGenerator()
        let clusterIcon = iconGenerator.icon(forSize: UInt(previousClusterMarker.markerCount), isSelected: false)
        previousClusterMarker.icon = clusterIcon
        selectedClusterMarker = nil
    }
    
    // 原有单个标记的处理逻辑不变
    let newCamera = GMSCameraPosition.camera(withTarget: clusterItem.position, zoom: propertyMapView.camera.zoom)
    propertyMapView.moveCamera(GMSCameraUpdate.setCamera(newCamera))
    
    if let previousMarker = propertyMapView.selectedMarker as? CustomMarker{
        previousMarker.isSelected = !previousMarker.isSelected
        let propertyMarker = createMarkerView(isSelected: previousMarker.isSelected)
        propertyMarker.markerPriceLabel.text = previousMarker.propertyListModal?.propertyPrice
        previousMarker.icon = propertyMarker.asImage()
    }
    
    let item = clusterItem as? POIItem
    if let tappedMarker = item?.marker as? CustomMarker{
        tappedMarker.isSelected = !tappedMarker.isSelected
        let propertyMarker = createMarkerView(isSelected: tappedMarker.isSelected)
        propertyMarker.markerPriceLabel.text = tappedMarker.propertyListModal?.propertyPrice
        tappedMarker.icon = propertyMarker.asImage()
        propertyMapView.selectedMarker = tappedMarker
    }
    
    isClusterTapped = false
    self.propertyListContainerForMap.isHidden = false
    self.propertyViewForMapCollectionView.reloadData()
    return true
}

这样修改后,点击集群图标时就会切换选中状态并更新图标,同时点击单个标记时会自动重置集群的选中状态,确保交互逻辑一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:20:57