简体   繁体   English

点击集合视图单元格以向 map 添加注释

[英]Tapping a collection view cell to add annotations to a map

Right now I have a map and a collection view that displays icons for the map.现在我有一个 map 和一个显示 map 图标的集合视图。 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; 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; similar to Apple Maps.类似于苹果地图。

 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
}
}
}

Currently, the functions that places the annotations of the respected category are not being called.目前,没有调用放置受尊重类别的注释的函数。 Is there a way to call these when an item from my collection view is tapped in order to achieve the desired results, or is there a better way to go about accomplishing this?当点击我的收藏视图中的项目以达到预期结果时,有没有办法调用这些,或者是否有更好的方法来 go 完成此操作?

在此处输入图像描述

There are 2 important missing steps in order to achieve what you asked with the code you provided:为了实现您使用您提供的代码提出的要求,有 2 个重要的缺失步骤:

  1. Be notified when the user taps a cell of your CollectionView and inform MapViewController of the set of annotation to display当用户点击 CollectionView 的单元格时收到通知,并通知 MapViewController 要显示的注释集
  2. Provide a MKMapViewDelegate to your MKMapView为您的 MKMapView 提供 MKMapViewDelegate

Step 1步骤1

For the sake of brevity, I'm going to assume that your ContentViewController holds a reference to MapViewController , so that it can call the appropriate setAnnotations() function when a cell is tapped.为简洁起见,我将假设您的ContentViewController持有对MapViewController的引用,以便在点击单元格时调用适当的 setAnnotations() function。

class ContentViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
  var mapViewController: MapViewController!
  let imageArray = ...
}

Next, we need to be informed when the user taps on one of those cells, for that we need to use a specific callback of UICollectionViewDelegate protocol:接下来,当用户点击其中一个单元格时,我们需要得到通知,为此我们需要使用UICollectionViewDelegate协议的特定回调:

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()
    }
  }
}

In this way, one of the three setXYZAnnotations function in MapViewController is called each time the user selects one of your cell.这样,每次用户选择您的一个单元格时,都会调用 MapViewController 中的三个 setXYZAnnotations function 之一。

We have a small issue to tackle before moving to the next step: MKMapView retains all the annotations added to it until those are removed.在进行下一步之前,我们有一个小问题需要解决:MKMapView 保留添加到其中的所有注释,直到这些注释被删除。 This means that each time you call one of the setXYZAnnontation function (hence, each time the user taps on a cell) a new set of annotation is appended to the map.这意味着每次调用setXYZAnnontation function(因此,每次用户点击单元格)时,都会将一组新注释附加到 map。 We have a simple way to discard all the annotations that were previously inserted into the map:我们有一个简单的方法来丢弃之前插入到 map 中的所有注释:

mapView.removeAnnotations(mapView.annotations)

This way, we're telling the map view to purge all the annotation it is currently holding.这样,我们告诉 map 视图清除它当前持有的所有注释。 Make sure to add this line right before calling mapView.addAnnotations(_) in each one of your setXYZAnnontation functions.确保在每个setXYZAnnontation函数中调用mapView.addAnnotations(_)之前添加此行。

Step 2第2步

When you add annotations or overlays on a map, it needs a way to be told how exactly you want those element to be rendered.当您在 map 上添加注释或覆盖时,需要一种方法来告知您希望这些元素如何呈现。 This is accomplished by a MKMapViewDelegate , just like a UICollectionView uses a UICollectionViewDataSource to know what UICollectionViewCell to use for a cell.这是由MKMapViewDelegate完成的,就像UICollectionView使用UICollectionViewDataSource来了解要用于单元格的UICollectionViewCell一样。

MapViewController is a good candidate to implement MKMapViewDelegate: MapViewController 是实现 MKMapViewDelegate 的理想选择:

class MapViewController: UIViewController, MKMapViewDelegate {
  override func viewDidLoad() {
    super.viewDidLoad()

    mapView.delegate = self
    ...
  }
}

Now, the protocol method you need to implement in MapViewController is mapView(_:viewFor:) , this function wants you to return an MKAnnotationView to associate with the specified annotation object you previously inserted.现在,您需要在 MapViewController 中实现的协议方法是mapView(_:viewFor:) ,这个 function 希望您返回一个MKAnnotationView以与您之前插入的指定注释 object 关联。

There are mainly two approaches you can take:您可以采取的方法主要有两种:

  • Simply return a MKPinAnnotationView : a bare, standard iOS-styled pin只需返回一个MKPinAnnotationView :一个裸露的、标准的 iOS 风格的 pin
    You can't customise the visual appearance of it other than its color除了颜色之外,您无法自定义它的视觉外观
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
  let pinView = MKPinAnnotationView()
  pinView.pinTintColor = .green
  return pinView
}
  • Return a MKAnnotaionView or subclass your own one, to fully customise the look of your annotation.返回一个MKAnnotaionView或子类您自己的,以完全自定义注释的外观。 In the following example I'm simply using a UIImage.在以下示例中,我只是使用 UIImage。
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
  let iconView = MKAnnotationView()
  iconView.image = UIImage(named: "pin_icon")
  return iconView
}

Of course, in your app you'd want to differentiate the look of the annotation view depending on the specific set of annotations selected by the user.当然,在您的应用程序中,您希望根据用户选择的特定注释集来区分注释视图的外观。

Note : if you have a large number of annotations inserted in a map, these two approaches might lead to performance problems.注意:如果您在 map 中插入了大量注释,这两种方法可能会导致性能问题。 In that case you need to register and dequeue reusable annotation views, so that the map can recycle them.在这种情况下,您需要注册和出列可重复使用的注释视图,以便map可以回收它们。 I suggest you to have a look at some quick tutorial and consult the MapKit documentation to deepen the subject.我建议您看一些快速教程并查阅MapKit文档以加深主题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM