使用 MKMapSnapshotter 创建可点击的地图预览
Create a clickable map preview using MKMapSnapshotter
我有一张地图,目前显示用户的当前位置,但没有针来显示他们的确切位置。我想让地图成为用户设置位置的照片。我只知道如何显示他们的设备在哪里,并需要他们能够设置他们的操作基础。我不需要具体地址。我只需要他们居住的城市。
然后我需要能够点击的图像。点击时,图像使 MapKit 全屏显示并具有交互性。然后他们可以放大地图并查看其他用户在哪里设置他们的操作基地。
我是编码新手,无法弄清楚如何允许用户设置永久位置,即使他们在全国各地移动也是如此。我也不知道如何设置 mapsnapshot 以及在点击时展开以显示完全可用的地图视图。
我目前只能询问我是否可以激活位置服务,然后在加载时显示他们的地图视图。这是代码:
import UIKit
import CoreLocation
import MapKit
class HomeTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, MKMapViewDelegate {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var mapPreviewImageView: UIImageView!
@IBOutlet weak var mapView: MKMapView!
let manager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.desiredAccuracy = kCLLocationAccuracyBest // battery
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
takeSnapShot()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
manager.stopUpdatingLocation()
render(location)
}
}
func render (_ location: CLLocation) {
let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapView.setRegion(region, animated: true)
}
func takeSnapShot() {
let location = CLLocation()
let mapSnapshotOptions = MKMapSnapshotter.Options()
let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapSnapshotOptions.region = region
// Set the scale of the image. We'll just use the scale of the current device, which is 2x scale on Retina screens.
mapSnapshotOptions.scale = UIScreen.main.scale
// Show buildings and Points of Interest on the snapshot
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.mapType = .satellite
let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
snapShotter.start() { snapshot, error in
guard let snapshot = snapshot else {
return
}
self.mapPreviewImageView.image = snapshot.image
}
}
}
提前感谢您的帮助。我真的需要在这个应用程序上取得一些进展,但我似乎找不到任何关于如何做到这一点的教程或网络搜索结果。
编辑:
我尝试添加一个函数,将我的 UIImage 转换为快照。我可以 return 一张图片,但它没有显示我的位置,而且它比我的 UIImage 小。我编辑了上面的代码以反映我所做的更改。我不知道我做错了什么。
在您的示例中,您正在创建 CLLocationManager
,但并未使用它。您正在使用 CLLocation()
。这显然没有与之相关的(有意义的)坐标。确保提供有效坐标。例如,让 didUpdateLocations
调用 takeSnapshot
:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
private weak var snapshotter: MKMapSnapshotter?
private lazy var manager: CLLocationManager = {
let manager = CLLocationManager()
manager.delegate = self
manager.distanceFilter = 20
return manager
}()
override func viewDidLoad() {
super.viewDidLoad()
if manager.authorizationStatus == .notDetermined {
manager.requestWhenInUseAuthorization()
}
manager.startUpdatingLocation()
}
func takeSnapshot(of location: CLLocation) {
snapshotter?.cancel() // cancel prior one, if any
let options = MKMapSnapshotter.Options()
options.camera = MKMapCamera(lookingAtCenter: location.coordinate, fromDistance: 1000, pitch: 0, heading: 0)
options.mapType = .satellite
options.size = imageView.bounds.size
let snapshotter = MKMapSnapshotter(options: options)
snapshotter.start() { snapshot, _ in
self.imageView.image = snapshot?.image
}
self.snapshotter = snapshotter
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last(where: { [=10=].horizontalAccuracy >= 0 } ) else { return }
takeSnapshot(of: location)
}
}
产生:
不相关的观察:
您正在使用 MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
。我个人并不认为度数跨度非常有用。我可能建议使用仪表,例如
options.region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
或使用 MKMapCamera
:
options.camera = MKMapCamera(lookingAtCenter: location.coordinate, fromDistance: 1000, pitch: 0, heading: 0)
如果您使用的是 satellite
地图类型,那么使用 showsBuildings
是没有意义的。 The docs 说:
The mapType
property must be set to MKMapType.standard
for extruded buildings to be displayed.
我不相信你要设置scale
。 The docs 说:
This property is set to a default value that corresponds to the resolution of the current device’s display.
此外,这个 属性 现在已经弃用了,无论如何。
不过,我建议设置图像的 size
。
我有一张地图,目前显示用户的当前位置,但没有针来显示他们的确切位置。我想让地图成为用户设置位置的照片。我只知道如何显示他们的设备在哪里,并需要他们能够设置他们的操作基础。我不需要具体地址。我只需要他们居住的城市。
然后我需要能够点击的图像。点击时,图像使 MapKit 全屏显示并具有交互性。然后他们可以放大地图并查看其他用户在哪里设置他们的操作基地。
我是编码新手,无法弄清楚如何允许用户设置永久位置,即使他们在全国各地移动也是如此。我也不知道如何设置 mapsnapshot 以及在点击时展开以显示完全可用的地图视图。
我目前只能询问我是否可以激活位置服务,然后在加载时显示他们的地图视图。这是代码:
import UIKit
import CoreLocation
import MapKit
class HomeTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, MKMapViewDelegate {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var mapPreviewImageView: UIImageView!
@IBOutlet weak var mapView: MKMapView!
let manager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.desiredAccuracy = kCLLocationAccuracyBest // battery
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
takeSnapShot()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
manager.stopUpdatingLocation()
render(location)
}
}
func render (_ location: CLLocation) {
let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapView.setRegion(region, animated: true)
}
func takeSnapShot() {
let location = CLLocation()
let mapSnapshotOptions = MKMapSnapshotter.Options()
let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapSnapshotOptions.region = region
// Set the scale of the image. We'll just use the scale of the current device, which is 2x scale on Retina screens.
mapSnapshotOptions.scale = UIScreen.main.scale
// Show buildings and Points of Interest on the snapshot
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.mapType = .satellite
let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
snapShotter.start() { snapshot, error in
guard let snapshot = snapshot else {
return
}
self.mapPreviewImageView.image = snapshot.image
}
}
}
提前感谢您的帮助。我真的需要在这个应用程序上取得一些进展,但我似乎找不到任何关于如何做到这一点的教程或网络搜索结果。
编辑:
我尝试添加一个函数,将我的 UIImage 转换为快照。我可以 return 一张图片,但它没有显示我的位置,而且它比我的 UIImage 小。我编辑了上面的代码以反映我所做的更改。我不知道我做错了什么。
在您的示例中,您正在创建 CLLocationManager
,但并未使用它。您正在使用 CLLocation()
。这显然没有与之相关的(有意义的)坐标。确保提供有效坐标。例如,让 didUpdateLocations
调用 takeSnapshot
:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
private weak var snapshotter: MKMapSnapshotter?
private lazy var manager: CLLocationManager = {
let manager = CLLocationManager()
manager.delegate = self
manager.distanceFilter = 20
return manager
}()
override func viewDidLoad() {
super.viewDidLoad()
if manager.authorizationStatus == .notDetermined {
manager.requestWhenInUseAuthorization()
}
manager.startUpdatingLocation()
}
func takeSnapshot(of location: CLLocation) {
snapshotter?.cancel() // cancel prior one, if any
let options = MKMapSnapshotter.Options()
options.camera = MKMapCamera(lookingAtCenter: location.coordinate, fromDistance: 1000, pitch: 0, heading: 0)
options.mapType = .satellite
options.size = imageView.bounds.size
let snapshotter = MKMapSnapshotter(options: options)
snapshotter.start() { snapshot, _ in
self.imageView.image = snapshot?.image
}
self.snapshotter = snapshotter
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last(where: { [=10=].horizontalAccuracy >= 0 } ) else { return }
takeSnapshot(of: location)
}
}
产生:
不相关的观察:
您正在使用
MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
。我个人并不认为度数跨度非常有用。我可能建议使用仪表,例如options.region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
或使用
MKMapCamera
:options.camera = MKMapCamera(lookingAtCenter: location.coordinate, fromDistance: 1000, pitch: 0, heading: 0)
如果您使用的是
satellite
地图类型,那么使用showsBuildings
是没有意义的。 The docs 说:The
mapType
property must be set toMKMapType.standard
for extruded buildings to be displayed.我不相信你要设置
scale
。 The docs 说:This property is set to a default value that corresponds to the resolution of the current device’s display.
此外,这个 属性 现在已经弃用了,无论如何。
不过,我建议设置图像的
size
。