ios - 点击 Collection View 单元格以向 map 添加注释

标签 ios swift xcode uicollectionview mapkit

现在我有一个 map 和一个显示 map 图标的 Collection View 。 I want to make it so that when one of the icons is selected it displays those different locations within that specific category on the map;类似于苹果 map 。

 import UIKit
 import MapKit

 //Creating an outline for the different locations of places on the map
 struct PlacesOnMap {
 var name: String
 var latitude: Double
 var longitude: Double

init(name: String, latitude: Double, longitude: Double) {
self.name = name
self.latitude = latitude
self.longitude = longitude
}
}

 class ContentViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

 //Properties of collectionView, that determine number of items in the section and allows a single cell to be reused over and over again
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
 }

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.mapIconImage.image = imageArray[indexPath.row]
cell.mapIconLabel.text! = imageNameArray[indexPath.row]
return cell
}

 //creating a constant for variables within the collection view such as the image and the title of the image
  let imageArray = [UIImage(named: "1"), UIImage(named: "2"), UIImage(named: "3")]
 let imageNameArray = ["image 1", "image 2", "image 3"]

 @IBOutlet var mapView: MKMapView!

 var places = [PlacesOnMap(name: "place 1", latitude: 28.551700, longitude: -81.374800),
 PlacesOnMap(name: "place 2", latitude: 28.553018, longitude: -81.374206),
 PlacesOnMap(name: "place 3", latitude: 28.553019, longitude: -81.367839)
]
 var buildings = [PlacesOnMap(name: "place 1", latitude: 28.556969, longitude: -81.364319),
 PlacesOnMap(name: "place 2", latitude: 28.558126, longitude: -81.364725)
]
 var recreation = [PlacesOnMap(name: "place 1", latitude: 28.54693, longitude: -81.393071),
 PlacesOnMap(name: "place 2", latitude: 28.538523, longitude: -81.385399),
 PlacesOnMap(name: "place 3", latitude: 28.542817, longitude: -81.378117),
 PlacesOnMap(name: "place 4", latitude: 28.538985, longitude: -81.404694)
]

override func viewDidLoad() {
super.viewDidLoad()

mapView?.delegate = self
}

func setPlacesAnnotations() {
let places = places.map { placeOnMap -> MKPointAnnotation in
let place = MKPointAnnotation()
place.coordinate =  CLLocationCoordinate2D(latitude: placeOnMap.latitude, longitude: placeOnMap.longitude)
place.title = placeOnMap.name
return place
}
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(places)
}

func setBuildingsAnnotations() {
let places = buildings.map { placeOnMap -> MKPointAnnotation in
let place = MKPointAnnotation()
place.coordinate =  CLLocationCoordinate2D(latitude: placeOnMap.latitude, longitude: placeOnMap.longitude)
place.title = placeOnMap.name
return place
}
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(places)
}

func setRecreationAnnotations() {
let places = recreation.map { placeOnMap -> MKPointAnnotation in
let place = MKPointAnnotation()
place.coordinate =  CLLocationCoordinate2D(latitude: placeOnMap.latitude, longitude: placeOnMap.longitude)
 place.title = placeOnMap.name
 return place
 }
 mapView.removeAnnotations(mapView.annotations)
 mapView.addAnnotations(places)
 }

 //calls the functions up above when a cell from the collection view is selected
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch (indexPath.item) {
case 0: setBuildingsAnnotations()
case 1: setPlacesAnnotations()
case 2: setRecreationAnnotations()
default:
    break
}
}
}

目前,未调用放置受尊重类别的注释的函数。当我的收藏 View 中的一个项目被点击以达到预期的结果时,有没有办法调用这些,或者有没有更好的方法来完成这个?

enter image description here

最佳答案

为了实现您使用您提供的代码提出的要求,有 2 个重要的缺失步骤:

  • 当用户点击 CollectionView 的单元格时收到通知,并通知 MapViewController 要显示的注释集
  • 为您的 MKMapView
  • 提供 MKMapViewDelegate

    第1步

    为简洁起见,我假设您的 ContentViewController持有对 MapViewController 的引用,以便它可以在点击单元格时调用适当的 setAnnotations() 函数。
    class ContentViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
      var mapViewController: MapViewController!
      let imageArray = ...
    }
    

    接下来,我们需要在用户点击其中一个单元格时得到通知,为此我们需要使用 UICollectionViewDelegate 的特定回调。协议(protocol):
    class ContentViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
      ...
      func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        switch (indexPath.item) {
        case 0:
          mapViewController.setPlacesAnnotations()
        case 1:
          mapViewController.setBuildingsAnnotations()
        case 2:
          mapViewController.setRecreationAnnotations()
        }
      }
    }
    

    这样,每次用户选择您的一个单元格时,都会调用 MapViewController 中的三个 setXYZAnnotations 函数之一。

    在进行下一步之前,我们有一个小问题需要解决:MKMapView 保留添加到其中的所有注释,直到这些注释被删除。这意味着每次调用 setXYZAnnontation 之一函数(因此,每次用户点击一个单元格时)一组新的注释被附加到 map 上。
    我们有一个简单的方法来丢弃之前插入到 map 中的所有注释:
    mapView.removeAnnotations(mapView.annotations)
    

    这样,我们告诉 map View 清除它当前持有的所有注释。确保在调用 mapView.addAnnotations(_) 之前添加此行在你的每一个 setXYZAnnontation职能。

    第2步

    当您在 map 上添加注释或叠加层时,需要一种方法来告知您希望如何准确地呈现这些元素。这是由 MKMapViewDelegate 完成的。 , 就像 UICollectionView使用 UICollectionViewDataSource知道什么UICollectionViewCell用于细胞。

    MapViewController 是实现 MKMapViewDelegate 的理想选择:
    class MapViewController: UIViewController, MKMapViewDelegate {
      override func viewDidLoad() {
        super.viewDidLoad()
    
        mapView.delegate = self
        ...
      }
    }
    

    现在,您需要在 MapViewController 中实现的协议(protocol)方法是 mapView(_:viewFor:) , 这个函数要你返回一个 MKAnnotationView与您之前插入的指定注释对象相关联。

    您可以采取的方法主要有两种:
  • 只需返回 MKPinAnnotationView : 一个裸露的、标准的 iOS 风格的 pin 📍
    除了颜色之外,您无法自定义它的视觉外观
  • func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
      let pinView = MKPinAnnotationView()
      pinView.pinTintColor = .green
      return pinView
    }
    
  • 返回 MKAnnotaionView或子类化您自己的,以完全自定义注释的外观。在下面的示例中,我只是使用 UIImage。
  • func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
      let iconView = MKAnnotationView()
      iconView.image = UIImage(named: "pin_icon")
      return iconView
    }
    

    当然,在您的应用程序中,您希望根据用户选择的特定注释集来区分注释 View 的外观。

    注意:如果您在 map 中插入了大量注释,这两种方法可能会导致性能问题。在这种情况下,您需要 registerdequeue可重复使用的注释 View ,以便 map 可以回收它们。我建议你看看一些quick tutorial并咨询MapKit文档以加深主题。

    关于ios - 点击 Collection View 单元格以向 map 添加注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62139045/

    相关文章:

    ios - 如何将 DataResponse<Any> 转换为 DefaultDataResponse

    swift - 条件运算符警告

    json - SWIFT URLResponse 无输出//Google map PI

    iOS tableview 在 UiBuilder 中显示为空

    ios - 从 videoView、Twilio 视频中清除一帧

    android - 使用flutter获取simcard信息

    swift - 如何在关闭先前的 View Controller 后更新表?

    swift - 在一个字符串中多次使用 NSAttributedString

    ios - 以编程方式创建 UIView

    ios - GMAP3 InfoWindows 不会在 iOS 浏览器上关闭