使用mapKit Swift显示与用户的距离(英里/公里) [英] Display the distance from user with mapKit Swift (miles/km)
问题描述
我一直试图在tableView上显示距离,但无法实现.该问题来自以下问题: CLLocationDistance转换.我已经检查了距离.在我的Location
类中使用此功能:
I have been attempting to display the distance on a tableView but I am unable to get it to happen. This question follows up from this question: CLLocationDistance conversion. I have checked the distance. Using this function in my Location
class:
// Get distance
func distance(to location: CLLocation) -> CLLocationDistance {
return location.distance(from: self.location)
}
如何获取用户当前位置:
How I get the users current location:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
mapView.setRegion(region, animated: true)
// Add a lastUserLocation to LocationManager and update it every time that the delegate receives a new location
LocationManager.shared.lastUserLocation = locations.last
LocationManager.shared.sortLocationsInPlace()
self.mapView.showsUserLocation = true
}
在LocationManager中排序功能:
Sort function in LocationManager:
func getSortedLocations(userLocation: CLLocation) -> [Location] {
return locations.sorted { (l1, l2) -> Bool in
return l1.distance(to: userLocation) < l2.distance(to: userLocation)
}
}
func sortLocationsInPlace() {
if let validLocation = lastUserLocation {
locations.sort { (l1, l2) -> Bool in
return l1.distance(to: validLocation) < l2.distance(to: validLocation)
}
}
}
cellForRowAt:
cellForRowAt:
var sortedLocations = [Location]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "locationCell", for: indexPath)
let location = sortedLocations[indexPath.row]
cell.textLabel?.text = location.name
return cell
}
更新
内部Location
类:
class Location {
var name: String
var latitude: Double
var longitude: Double
var location:CLLocation {
return CLLocation(latitude: latitude, longitude: longitude)
}
init?(json: JSON) {
guard let name = json["name"] as? String, let latitude = json["latitude"] as? Double, let longitude = json["longitude"] as? Double else { return nil }
self.name = name
self.latitude = latitude
self.longitude = longitude
}
func distance(to location: CLLocation) -> CLLocationDistance {
return location.distance(from: self.location)
}
}
推荐答案
考虑到您的代码,我在做一些假设:
Considering your code, I am making some assumptions:
- 您的
sortedLocations
数组具有从 JSON 或其他提取的位置. - 您在加载您的文件之前,先致电 startUpdatingLocation()或类似名称.数据.
- 您正在
didUpdateLocations
中接收更新. - 您的
LocationManager
将您所有位置的有序副本保存在名为locations
的变量中,该变量是您在didUpdateLocations
内部订购的变量.
- Your
sortedLocations
array has different locations that you extracted from a JSON or whatever. - You call startUpdatingLocation() or similar somewhere before loading your data.
- You are receiving updates in your
didUpdateLocations
. - Your
LocationManager
keeps an ordered copy of all your locations in a variable calledlocations
, the one you are ordering insidedidUpdateLocations
.
考虑过,据我了解,您想要做的是显示根据参考位置排序的sortedLocations
.
That considered, what I understand you want to do is to display your sortedLocations
ordered according to a reference location.
缺少的是一旦收到您的用户位置,便更新您的UITableView
数据.您有两个主要选择:
What is missing is to update your UITableView
data once your user location is received. You have two main options:
- 仅当您已经由
didUpdateLocations
检索到您的第一个用户位置时,才加载UITableView
. - 在获取新位置后通过在
didUpdateLocations
中调用tableView.reloadData()
强制执行UITableView
更新.每当您收到位置更新信息时,都会重新绘制您的列表,并按位置对它们进行排序.
- To only load your
UITableView
once you have already your first user location retrieved bydidUpdateLocations
. - To force a
UITableView
update once you get a new location, by callingtableView.reloadData()
insidedidUpdateLocations
. This will redraw your list every time you receive a location update, sorting them by location.
但是,在任何情况下,您都需要替换cellForRow
文本以显示距离而不是location.name
:
However, in any of those cases you need to replace your cellForRow
text to display your distance instead of location.name
:
// Distance in meters
cell.textLabel?.text = String(location.distance(to: LocationManager.shared.lastUserLocation!))
// Distance in miles
cell.textLabel?.text = String(location.distance(to: LocationManager.shared.lastUserLocation!)*0.00062137)
然后更新您的didUpdateLocations
:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
mapView.setRegion(region, animated: true)
// Add a lastUserLocation to LocationManager and update it every time that the delegate receives a new location
LocationManager.shared.lastUserLocation = location
LocationManager.shared.sortLocationsInPlace()
sortedLocations = LocationManager.shared.locations
tableView.reloadData()
self.mapView.showsUserLocation = true
}
}
使用当前代码,您正在将所有距离与self.location
变量进行比较,该变量显然没有在任何地方初始化.
With your current code you are comparing all distances with a self.location
variable that its not being initialised anywhere apparently.
这篇关于使用mapKit Swift显示与用户的距离(英里/公里)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!