在 Swift 3 的自定义视图中使用 Google 地图绘制多段线
Draw polyline using Google Maps in custom view with Swift 3
我正在尝试在自定义 UIView 上使用 Google 地图绘制两地之间的路线,但无法正确实施。我的自定义视图是 mapViewX。我已经使用 pods 安装了 google sdk,其中包括 pod 'GoogleMaps' 和 pod 'GooglePlaces'。我将自定义视图 Class 设为 'GMSMapView'。我的代码是:
@IBOutlet weak var mapViewX: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960))
path.add(CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677))
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
请帮忙!
在这里工作正常。确保设置 GMSCameraPosition
.
的正确坐标
编辑
要绘制两个坐标之间的路线,请使用Google Maps Direction API
类似于:
let origin = "\(37.778483),\(-122.513960)"
let destination = "\(37.706753),\(-122.418677)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=[YOUR-API-KEY]"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
}
了解更多信息 - Directions API Developer's Guide
要在 2 个坐标之间绘制路线,您需要向 Google 地图路线 API 发出请求并解析其响应。因此,您首先需要为您的请求获取一个 API 密钥。您可以获得一个 here,方法是创建一个项目并在此项目中启用 Google 地图方向 API。
假设您安装了 Google Maps SDK,您需要向 API 方向发出请求,然后解析其响应。解析响应 JSON 后,您可以创建 GMSPath 对象。我更喜欢使用具有两个输入的函数来执行此操作,开始和结束 CLLocationCoordinate2D 对象以及 returns 成功时的 GMSPath 或失败时的错误。下面的代码在Swift 3.
我的 class 及其函数如下所示:
import Foundation
import CoreLocation
import GoogleMaps
class SessionManager {
let GOOGLE_DIRECTIONS_API_KEY = "INSERT_YOUR_API_KEY_HERE"
func requestDirections(from start: CLLocationCoordinate2D, to end: CLLocationCoordinate2D, completionHandler: @escaping ((_ response: GMSPath?, _ error: Error?) -> Void)) {
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(start.latitude),\(start.longitude)&destination=\(end.latitude),\(end.longitude)&key=\(GOOGLE_DIRECTIONS_API_KEY)") else {
let error = NSError(domain: "LocalDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create object URL"])
print("Error: \(error)")
completionHandler(nil, error)
return
}
// Set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { (data, response, error) in
// Check if there is an error.
guard error == nil else {
DispatchQueue.main.async {
print("Google Directions Request Error: \((error!)).")
completionHandler(nil, error)
}
return
}
// Make sure data was received.
guard let data = data else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to receive data"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
do {
// Convert data to dictionary.
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to convert JSON to Dictionary"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
// Check if the the Google Direction API returned a status OK response.
guard let status: String = json["status"] as? String, status == "OK" else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 3, userInfo: [NSLocalizedDescriptionKey: "Google Direction API did not return status OK"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
print("Google Direction API response:\n\(json)")
// We only need the 'points' key of the json dictionary that resides within.
if let routes: [Any] = json["routes"] as? [Any], routes.count > 0, let routes0: [String: Any] = routes[0] as? [String: Any], let overviewPolyline: [String: Any] = routes0["overview_polyline"] as? [String: Any], let points: String = overviewPolyline["points"] as? String {
// We need the get the first object of the routes array (route0), then route0's overview_polyline and finally overview_polyline's points object.
if let path: GMSPath = GMSPath(fromEncodedPath: points) {
DispatchQueue.main.async {
completionHandler(path, nil)
}
return
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 5, userInfo: [NSLocalizedDescriptionKey: "Failed to create GMSPath from encoded points string."])
completionHandler(nil, error)
}
return
}
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 4, userInfo: [NSLocalizedDescriptionKey: "Failed to parse overview polyline's points"])
completionHandler(nil, error)
}
return
}
} catch let error as NSError {
DispatchQueue.main.async {
completionHandler(nil, error)
}
return
}
}
task.resume()
}
}
然后你可以像这样在你的 viewDidLoad
中使用它:
@IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let sessionManager = SessionManager()
let start = CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960)
let end = CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677)
sessionManager.requestDirections(from: start, to: end, completionHandler: { (path, error) in
if let error = error {
print("Something went wrong, abort drawing!\nError: \(error)")
} else {
// Create a GMSPolyline object from the GMSPath
let polyline = GMSPolyline(path: path!)
// Add the GMSPolyline object to the mapView
polyline.map = self.mapView
// Move the camera to the polyline
let bounds = GMSCoordinateBounds(path: path!)
let cameraUpdate = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 40, left: 15, bottom: 10, right: 15))
self.mapView.animate(with: cameraUpdate)
}
})
}
希望您觉得它有用。
Swift 4
创建全局变量。
var sourceLat = 0.0
var sourceLong = 0.0
var DestinationLat = 0.0
var DestinationLong = 0.0
var startLOC = CLLocation()
var endLOC = CLLocation()
安装 Pod Alamofire 和 SwiftJSON。
pod 'Alamofire', '~> 4.5'
pod 'SwiftyJSON'
创建源和目标之间绘制路线的函数。
func drawPath(startLocation: CLLocation, endLocation: CLLocation)
{
let origin = "\(startLocation.coordinate.latitude),\(startLocation.coordinate.longitude)"
let destination = "\(endLocation.coordinate.latitude),\(endLocation.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
//print(response.request as Any) // original URL request
//print(response.response as Any) // HTTP URL response
//print(response.data as Any) // server data
//print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
print(json)
// print route using Polyline
DispatchQueue.global(qos: .default).async(execute: {() -> Void in
// Do something...
DispatchQueue.main.async(execute: {() -> Void in
// self.hideHUD()
})
})
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapViewBus
}
}
}
创建按钮操作为其提供源路由和目标路由。提供纬度和经度。之后粘贴代码。
// Route Source & Destination
self.startLOC = CLLocation(latitude: sourceLat, longitude: sourceLong)
self.endLOC = CLLocation(latitude: DestinationLat, longitude: DestinationLong)
drawPath(startLocation: startLOC, endLocation: endLOC)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: sourceLat, longitude: sourceLong)
// marker.icon = userImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
marker.title = "Source"
marker.map = mapViewBus
let markerr = GMSMarker()
markerr.position = CLLocationCoordinate2D(latitude: DestinationLat, longitude: DestinationLong)
// markerr.icon = washerImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
markerr.title = "Desintation"
markerr.map = mapViewBus
let camera = GMSCameraPosition.camera(withLatitude: sourceLat, longitude: sourceLong, zoom: 14.0)
self.mapViewBus.camera = camera
self.mapViewBus.animate(to: camera)
我正在尝试在自定义 UIView 上使用 Google 地图绘制两地之间的路线,但无法正确实施。我的自定义视图是 mapViewX。我已经使用 pods 安装了 google sdk,其中包括 pod 'GoogleMaps' 和 pod 'GooglePlaces'。我将自定义视图 Class 设为 'GMSMapView'。我的代码是:
@IBOutlet weak var mapViewX: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960))
path.add(CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677))
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
请帮忙!
在这里工作正常。确保设置 GMSCameraPosition
.
编辑
要绘制两个坐标之间的路线,请使用Google Maps Direction API
类似于:
let origin = "\(37.778483),\(-122.513960)"
let destination = "\(37.706753),\(-122.418677)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=[YOUR-API-KEY]"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
}
了解更多信息 - Directions API Developer's Guide
要在 2 个坐标之间绘制路线,您需要向 Google 地图路线 API 发出请求并解析其响应。因此,您首先需要为您的请求获取一个 API 密钥。您可以获得一个 here,方法是创建一个项目并在此项目中启用 Google 地图方向 API。
假设您安装了 Google Maps SDK,您需要向 API 方向发出请求,然后解析其响应。解析响应 JSON 后,您可以创建 GMSPath 对象。我更喜欢使用具有两个输入的函数来执行此操作,开始和结束 CLLocationCoordinate2D 对象以及 returns 成功时的 GMSPath 或失败时的错误。下面的代码在Swift 3.
我的 class 及其函数如下所示:
import Foundation
import CoreLocation
import GoogleMaps
class SessionManager {
let GOOGLE_DIRECTIONS_API_KEY = "INSERT_YOUR_API_KEY_HERE"
func requestDirections(from start: CLLocationCoordinate2D, to end: CLLocationCoordinate2D, completionHandler: @escaping ((_ response: GMSPath?, _ error: Error?) -> Void)) {
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(start.latitude),\(start.longitude)&destination=\(end.latitude),\(end.longitude)&key=\(GOOGLE_DIRECTIONS_API_KEY)") else {
let error = NSError(domain: "LocalDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create object URL"])
print("Error: \(error)")
completionHandler(nil, error)
return
}
// Set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { (data, response, error) in
// Check if there is an error.
guard error == nil else {
DispatchQueue.main.async {
print("Google Directions Request Error: \((error!)).")
completionHandler(nil, error)
}
return
}
// Make sure data was received.
guard let data = data else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to receive data"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
do {
// Convert data to dictionary.
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to convert JSON to Dictionary"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
// Check if the the Google Direction API returned a status OK response.
guard let status: String = json["status"] as? String, status == "OK" else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 3, userInfo: [NSLocalizedDescriptionKey: "Google Direction API did not return status OK"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
print("Google Direction API response:\n\(json)")
// We only need the 'points' key of the json dictionary that resides within.
if let routes: [Any] = json["routes"] as? [Any], routes.count > 0, let routes0: [String: Any] = routes[0] as? [String: Any], let overviewPolyline: [String: Any] = routes0["overview_polyline"] as? [String: Any], let points: String = overviewPolyline["points"] as? String {
// We need the get the first object of the routes array (route0), then route0's overview_polyline and finally overview_polyline's points object.
if let path: GMSPath = GMSPath(fromEncodedPath: points) {
DispatchQueue.main.async {
completionHandler(path, nil)
}
return
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 5, userInfo: [NSLocalizedDescriptionKey: "Failed to create GMSPath from encoded points string."])
completionHandler(nil, error)
}
return
}
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 4, userInfo: [NSLocalizedDescriptionKey: "Failed to parse overview polyline's points"])
completionHandler(nil, error)
}
return
}
} catch let error as NSError {
DispatchQueue.main.async {
completionHandler(nil, error)
}
return
}
}
task.resume()
}
}
然后你可以像这样在你的 viewDidLoad
中使用它:
@IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let sessionManager = SessionManager()
let start = CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960)
let end = CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677)
sessionManager.requestDirections(from: start, to: end, completionHandler: { (path, error) in
if let error = error {
print("Something went wrong, abort drawing!\nError: \(error)")
} else {
// Create a GMSPolyline object from the GMSPath
let polyline = GMSPolyline(path: path!)
// Add the GMSPolyline object to the mapView
polyline.map = self.mapView
// Move the camera to the polyline
let bounds = GMSCoordinateBounds(path: path!)
let cameraUpdate = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 40, left: 15, bottom: 10, right: 15))
self.mapView.animate(with: cameraUpdate)
}
})
}
希望您觉得它有用。
Swift 4
创建全局变量。
var sourceLat = 0.0
var sourceLong = 0.0
var DestinationLat = 0.0
var DestinationLong = 0.0
var startLOC = CLLocation()
var endLOC = CLLocation()
安装 Pod Alamofire 和 SwiftJSON。
pod 'Alamofire', '~> 4.5'
pod 'SwiftyJSON'
创建源和目标之间绘制路线的函数。
func drawPath(startLocation: CLLocation, endLocation: CLLocation)
{
let origin = "\(startLocation.coordinate.latitude),\(startLocation.coordinate.longitude)"
let destination = "\(endLocation.coordinate.latitude),\(endLocation.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
//print(response.request as Any) // original URL request
//print(response.response as Any) // HTTP URL response
//print(response.data as Any) // server data
//print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
print(json)
// print route using Polyline
DispatchQueue.global(qos: .default).async(execute: {() -> Void in
// Do something...
DispatchQueue.main.async(execute: {() -> Void in
// self.hideHUD()
})
})
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapViewBus
}
}
}
创建按钮操作为其提供源路由和目标路由。提供纬度和经度。之后粘贴代码。
// Route Source & Destination
self.startLOC = CLLocation(latitude: sourceLat, longitude: sourceLong)
self.endLOC = CLLocation(latitude: DestinationLat, longitude: DestinationLong)
drawPath(startLocation: startLOC, endLocation: endLOC)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: sourceLat, longitude: sourceLong)
// marker.icon = userImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
marker.title = "Source"
marker.map = mapViewBus
let markerr = GMSMarker()
markerr.position = CLLocationCoordinate2D(latitude: DestinationLat, longitude: DestinationLong)
// markerr.icon = washerImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
markerr.title = "Desintation"
markerr.map = mapViewBus
let camera = GMSCameraPosition.camera(withLatitude: sourceLat, longitude: sourceLong, zoom: 14.0)
self.mapViewBus.camera = camera
self.mapViewBus.animate(to: camera)