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
相关产品推荐
相关产品推荐

