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

iOS Swift 4中如何通过CollectionView筛选GoogleMapView标记

嘿,这个需求我之前做过,给你一步步拆解怎么实现CollectionView筛选GoogleMap标记的功能,超实用的!

核心思路

我们要把CollectionView的分类选项和地图上的标记做绑定:选中某个分类时,只显示对应类型的标记,隐藏其他分类的;选「全部」时则展示所有标记。下面是具体实现步骤:

1. 完善数据模型,增加分类标识

首先给你的Location结构体加个分类字段,这样才能区分每个标记属于哪一类。推荐用枚举来管理分类,更规范:

// 定义分类枚举
enum LocationCategory: String, CaseIterable {
    case beautyCare = "Beauty Care"
    case childCare = "Child Care"
    // 可以继续加其他分类,比如petCare、food等
}

// 完善位置模型
struct Location { 
    let icon: UIImage 
    let latitude: CLLocationDegrees 
    let longitude: CLLocationDegrees
    let category: LocationCategory // 新增分类字段
}

2. 改造MapViewController,管理标记和CollectionView

让你的ViewController同时遵守CollectionView的数据源和代理协议,并且新增变量来管理标记集合和当前选中的分类:

class MapViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
    @IBOutlet weak var mapView: GMSMapView!
    @IBOutlet weak var categoryCollectionView: UICollectionView!
    
    // 初始化带分类的位置数据
    let locations: [Location] = [
        Location(icon: UIImage(named:"beautycare.png")!, latitude: 36.771873, longitude: -119.750724, category: .beautyCare),
        Location(icon: UIImage(named:"childcare.png")!, latitude: 36.771930, longitude: -119.7613, category: .childCare)
        // 更多位置数据...
    ]
    
    // 按分类存储所有地图标记,方便快速筛选
    private var categoryMarkers: [LocationCategory: [GMSMarker]] = [:]
    // 当前选中的分类,nil代表显示全部
    private var selectedCategory: LocationCategory?

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView.delegate = self
        setupCollectionView()
        setupMapMarkers()
    }
}

3. 初始化地图标记和CollectionView

在viewDidLoad里调用这两个方法,完成标记创建和CollectionView的基础配置:

// 创建所有地图标记并按分类分组
private func setupMapMarkers() {
    for location in locations {
        let marker = GMSMarker()
        marker.position = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
        marker.icon = location.icon
        marker.map = mapView // 默认全部显示
        
        // 将标记按分类存入字典
        if categoryMarkers[location.category] == nil {
            categoryMarkers[location.category] = []
        }
        categoryMarkers[location.category]?.append(marker)
    }
}

// 配置CollectionView的布局和基础设置
private func setupCollectionView() {
    categoryCollectionView.dataSource = self
    categoryCollectionView.delegate = self
    
    // 注册cell(实际项目建议用自定义cell,这里用系统cell做演示)
    categoryCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CategoryCell")
    
    // 设置横向流式布局
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    layout.itemSize = CGSize(width: 120, height: 40)
    layout.minimumInteritemSpacing = 8
    categoryCollectionView.collectionViewLayout = layout
}

4. 实现CollectionView数据源方法

让CollectionView显示分类选项,包括「全部」:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return LocationCategory.allCases.count + 1 // +1是「全部」选项
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCell", for: indexPath)
    
    // 设置cell标题
    let title: String
    if indexPath.item == 0 {
        title = "全部"
    } else {
        let category = LocationCategory.allCases[indexPath.item - 1]
        title = category.rawValue
    }
    
    // 添加显示标题的Label(自定义cell可以忽略这段,直接用cell的属性)
    if let label = cell.contentView.subviews.first as? UILabel {
        label.text = title
    } else {
        let label = UILabel(frame: cell.contentView.bounds)
        label.textAlignment = .center
        label.textColor = .white
        label.text = title
        cell.contentView.addSubview(label)
    }
    
    // 设置选中样式
    cell.backgroundColor = (selectedCategory == (indexPath.item == 0 ? nil : LocationCategory.allCases[indexPath.item - 1])) ? .systemBlue : .lightGray
    cell.layer.cornerRadius = 8
    return cell
}

5. 实现筛选逻辑:CollectionView选中事件

点击分类时,更新地图标记的显示状态:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    // 更新当前选中的分类
    selectedCategory = indexPath.item == 0 ? nil : LocationCategory.allCases[indexPath.item - 1]
    // 更新标记显示
    updateMarkerVisibility()
    // 刷新CollectionView选中样式
    collectionView.reloadData()
}

// 控制标记的显示/隐藏
private func updateMarkerVisibility() {
    // 先隐藏所有标记
    categoryMarkers.values.flatMap { $0 }.forEach { $0.map = nil }
    
    // 根据选中分类显示对应标记
    if let targetCategory = selectedCategory {
        categoryMarkers[targetCategory]?.forEach { $0.map = mapView }
    } else {
        // 显示所有标记
        categoryMarkers.values.flatMap { $0 }.forEach { $0.map = mapView }
    }
}

额外优化建议

  • 自定义CollectionViewCell:给cell加圆角、阴影、选中动画,让交互更友好;
  • 标记联动CollectionView:点击地图上的标记时,自动选中对应的分类选项;
  • 大数据量优化:如果标记数量特别多,可以只创建当前需要显示的标记,避免内存占用过高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:37:40