在iOS中的GMSMapView上绘制两地之间的路线

Posted

技术标签:

【中文标题】在iOS中的GMSMapView上绘制两地之间的路线【英文标题】:Drawing Route Between Two Places on GMSMapView in iOS 【发布时间】:2014-03-21 05:23:38 【问题描述】:

我正在开发一个 ios 应用程序。在那个应用程序中,我有 2 个从和到的字段。我使用 Google 自动完成 API 输入了地址。我还能够获取 2 个地方的 LatitudeLongitude,并能够在 GMSMapView 上显示标记。

现在我想在这两个地方之间画出路线。当我们使用MKMapView 时,我找到了解决方案。但我无法找到GMSMapView 的解决方案。请帮我在GMSMapView 中画出这两点之间的路线。

如果可能的话,请给我一些重要的链接。

谢谢。

【问题讨论】:

【参考方案1】:
`first get all points coordinates which are coming in route then add these points latitude and longitude in path in will draw path according to that`


GMSCameraPosition *cameraPosition=[GMSCameraPosition cameraWithLatitude:18.5203 longitude:73.8567 zoom:12];
_mapView =[GMSMapView mapWithFrame:CGRectZero camera:cameraPosition];
_mapView.myLocationEnabled=YES;
GMSMarker *marker=[[GMSMarker alloc]init];
marker.position=CLLocationCoordinate2DMake(18.5203, 73.8567);
marker.icon=[UIImage imageNamed:@"aaa.png"] ;
marker.groundAnchor=CGPointMake(0.5,0.5);
marker.map=_mapView;
GMSMutablePath *path = [GMSMutablePath path];   
[path addCoordinate:CLLocationCoordinate2DMake(@(18.520).doubleValue,@(73.856).doubleValue)];
[path addCoordinate:CLLocationCoordinate2DMake(@(16.7).doubleValue,@(73.8567).doubleValue)];

GMSPolyline *rectangle = [GMSPolyline polylineWithPath:path];
rectangle.strokeWidth = 2.f;
rectangle.map = _mapView;
self.view=_mapView;

【讨论】:

感谢您的回答。它解决了我的问题。小距离没关系。长距离需要时间。有什么解决办法吗? 从一个地方到一个地方创建一条线。我希望它会创建一个带有动画的曲折路径。怎么可能? 您应该在 for 循环或使用函数中提供所有点。或者您可能没有插入内部点。 出现错误:ld: library not found for -lPods-Google-Maps-iOS-SDK clang: error: linker command failed with exit code 1 (use -v to see invocation) 直接下载库并添加到你的项目中【参考方案2】:

我已经编写了以下代码,应该可以为您解决问题:

- (void)drawRoute

    [self fetchPolylineWithOrigin:myOrigin destination:myDestination completionHandler:^(GMSPolyline *polyline)
     
         if(polyline)
             polyline.map = self.myMap;
     ];


- (void)fetchPolylineWithOrigin:(CLLocation *)origin destination:(CLLocation *)destination completionHandler:(void (^)(GMSPolyline *))completionHandler

    NSString *originString = [NSString stringWithFormat:@"%f,%f", origin.coordinate.latitude, origin.coordinate.longitude];
    NSString *destinationString = [NSString stringWithFormat:@"%f,%f", destination.coordinate.latitude, destination.coordinate.longitude];
    NSString *directionsAPI = @"https://maps.googleapis.com/maps/api/directions/json?";
    NSString *directionsUrlString = [NSString stringWithFormat:@"%@&origin=%@&destination=%@&mode=driving", directionsAPI, originString, destinationString];
    NSURL *directionsUrl = [NSURL URLWithString:directionsUrlString];


    NSURLSessionDataTask *fetchDirectionsTask = [[NSURLSession sharedSession] dataTaskWithURL:directionsUrl completionHandler:
         ^(NSData *data, NSURLResponse *response, NSError *error)
         
             NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
             if(error)
             
                 if(completionHandler)
                     completionHandler(nil);
                 return;
             

             NSArray *routesArray = [json objectForKey:@"routes"];

             GMSPolyline *polyline = nil;
             if ([routesArray count] > 0)
             
                 NSDictionary *routeDict = [routesArray objectAtIndex:0];
                 NSDictionary *routeOverviewPolyline = [routeDict objectForKey:@"overview_polyline"];
                 NSString *points = [routeOverviewPolyline objectForKey:@"points"];
                 GMSPath *path = [GMSPath pathFromEncodedPath:points];
                 polyline = [GMSPolyline polylineWithPath:path];
             

             // run completionHandler on main thread                                           
             dispatch_sync(dispatch_get_main_queue(), ^
                 if(completionHandler)
                      completionHandler(polyline);
             );
         ];
    [fetchDirectionsTask resume];

【讨论】:

我们可以为此获取 Swift 版本吗? @Tarek,小心 ==> Google Maps iOA SDK 要求所有绘图事件都在主线程上完成。因此,对于您的第二种方法,您必须将所有制造商设置代码放入 dispatch_get_main_queue() 闭包中。否则,请准备好让您的甜蜜应用崩溃。 @Monusingh 你说得对!我刚刚修改了代码,以便完成处理程序在主线程上运行。谢谢! 您好,我在 对 iOS 版 Google Maps SDK 的所有调用都必须从 UI 线程进行的 polyline = [GMSPolyline polylineWithPath:path]; 行上遇到崩溃 我将此代码转换为 swift,但此处出现错误,如果 completionHandler completionHandler(nil) 。错误是:'(GMSPolyline?) -> Void' 不能转换为 'Bool'【参考方案3】:

为swift 3绘制折线

func getPolylineRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D)

        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)

        let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=true&mode=driving&key=YOURKEY")!

        let task = session.dataTask(with: url, completionHandler: 
            (data, response, error) in
            if error != nil 
                print(error!.localizedDescription)
                self.activityIndicator.stopAnimating()
            
            else 
                do 
                    if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]

                        guard let routes = json["routes"] as? NSArray else 
                            DispatchQueue.main.async 
                                self.activityIndicator.stopAnimating()
                            
                            return
                        

                        if (routes.count > 0) 
                            let overview_polyline = routes[0] as? NSDictionary
                            let dictPolyline = overview_polyline?["overview_polyline"] as? NSDictionary

                            let points = dictPolyline?.object(forKey: "points") as? String

                            self.showPath(polyStr: points!)

                            DispatchQueue.main.async 
                                self.activityIndicator.stopAnimating()

                                let bounds = GMSCoordinateBounds(coordinate: source, coordinate: destination)
                                let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
                                self.mapView!.moveCamera(update)
                            
                        
                        else 
                            DispatchQueue.main.async 
                                self.activityIndicator.stopAnimating()
                            
                        
                    
                
                catch 
                    print("error in JSONSerialization")
                    DispatchQueue.main.async 
                        self.activityIndicator.stopAnimating()
                    
                
            
        )
        task.resume()
    

    func showPath(polyStr :String)
        let path = GMSPath(fromEncodedPath: polyStr)
        let polyline = GMSPolyline(path: path)
        polyline.strokeWidth = 3.0
        polyline.strokeColor = UIColor.red
        polyline.map = mapView // Your map view
    

注意:您需要将 googleDirection API 密钥放入 URL。

【讨论】:

谢谢,在一些小的调整上帮了我很多忙! 嘿,我正在使用你的代码,但我没有得到结果是否需要任何 json 文件? 您需要使用正确的 googleAPI 密钥,并且还需要为该密钥启用 googleDirection 功能。【参考方案4】:

如果有人正在为@Tarek 的答案寻找 Swift 3.0,您可以使用它。这也使用Alamofire 和SwiftyJSON。

func drawPath()

    let origin = "\(currentLocation.latitude),\(currentLocation.longitude)"
    let destination = "\(destinationLoc.latitude),\(destinationLoc.longitude)"


    let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=YOURKEY"

    Alamofire.request(url).responseJSON  response in
      print(response.request)  // original URL request
      print(response.response) // HTTP URL response
      print(response.data)     // server data
      print(response.result)   // result of response serialization

      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.init(path: path)
        polyline.map = self.mapView
      
    
  

【讨论】:

【参考方案5】:

这是 johny kumar 答案的 Swift 翻译。

let cameraPositionCoordinates = CLLocationCoordinate2D(latitude: 18.5203, longitude: 73.8567)
    let cameraPosition = GMSCameraPosition.cameraWithTarget(cameraPositionCoordinates, zoom: 12)

    let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: cameraPosition)
    mapView.myLocationEnabled = true

    let marker = GMSMarker()
    marker.position = CLLocationCoordinate2DMake(18.5203, 73.8567)
    marker.groundAnchor = CGPointMake(0.5, 0.5)
    marker.map = mapView

    let path = GMSMutablePath()
    path.addCoordinate(CLLocationCoordinate2DMake(18.520, 73.856))
    path.addCoordinate(CLLocationCoordinate2DMake(16.7, 73.8567))

    let rectangle = GMSPolyline(path: path)
    rectangle.strokeWidth = 2.0
    rectangle.map = mapView

    self.view = mapView

【讨论】:

这画了一条直线 :(【参考方案6】:

- Swift 3.0 & XCode 8.0 Staright Line :(

let cameraPosition = GMSCameraPosition.camera(withLatitude: 18.5203, longitude: 73.8567, zoom: 12)
        self.mapView = GMSMapView.map(withFrame: CGRect.zero, camera: cameraPosition)
        self.mapView.isMyLocationEnabled = true
        let marker = GMSMarker()
        marker.position = CLLocationCoordinate2DMake(18.5203, 73.8567)
       // marker.icon = UIImage(named: "aaa.png")!
        marker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
        marker.map = mapView
        let path = GMSMutablePath()
        path.add(CLLocationCoordinate2DMake(CDouble((18.520)), CDouble((73.856))))
        path.add(CLLocationCoordinate2DMake(CDouble((16.7)), CDouble((73.8567))))
        let rectangle = GMSPolyline.init(path: path)
        rectangle.strokeWidth = 2.0
        rectangle.map = mapView
        self.view = mapView

【讨论】:

【参考方案7】:

向 Google Directions API 发出 URL 请求,当您收到 JSON 文件时,请执行所有步骤并解码点对象。

【讨论】:

【参考方案8】:

我在 xCode 8.3.3 和 Swift 3.1 中使用 AlamoFire 和 SwiftyJson 实现了它。 将路径的绘制放在一个只需要两个参数的函数中

字符串来源示例“48.7788,9.22222” 和一个字符串目标示例“49.3212232,8.334151”

func drawPath (origin: String, destination: String) 
    /* set the parameters needed */ 
    String prefTravel = "walking" /* options are driving, walking, bicycling */
    String gmapKey = "Ask Google"
    /* Make the url */
    let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=\(prefTravel)&key=" + gmapKey)

    /* Fire the request */
    Alamofire.request(url!).responseJSON(responseData) -> Void in
        if((responseData.result.value) != nil) 
            /* read the result value */
            let swiftyJsonVar = JSON(responseData.result.value!)
            /* only get the routes object */
            if let resData = swiftyJsonVar["routes"].arrayObject 
                let routes = resData as! [[String: AnyObject]]
                /* loop the routes */
                if routes.count > 0 
                    for rts in routes 
                       /* get the point */
                       let overViewPolyLine = rts["overview_polyline"]?["points"]
                       let path = GMSMutablePath(fromEncodedPath: overViewPolyLine as! String)
                       /* set up poly line */
                       let polyline = GMSPolyline.init(path: path)
                       polyline.strokeWidth = 2
                       polyline.map = self.mapView
                    
                
            
        
    

【讨论】:

【参考方案9】:

您好,您可以使用“LRouteController”,这是显示两点之间道路路线的最佳方式,例如:

[_routeController getPolyline With Locations: (Array of first and last location)]

试试吧,希望能解决你的问题。

【讨论】:

【参考方案10】:

来自 Google Directions API的DirectionResponse@NSLogs 对于查看您正在处理的内容很有用。

[[GMDirectionService sharedInstance] getDirectionsFrom:origin to:destination          succeeded:^(GMDirection *directionResponse)    
if ([directionResponse statusOK])
    NSLog(@"Duration : %@", [directionResponse durationHumanized]);
    NSLog(@"Distance : %@", [directionResponse distanceHumanized]);
    NSArray *routes = [[directionResponse directionResponse] objectForKey:@"routes"];
    // NSLog(@"Route : %@", [[directionResponse directionResponse] objectForKey:@"routes"]);

    GMSPath *path = [GMSPath pathFromEncodedPath:routes[0][@"overview_polyline"]  [@"points"]];
    GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
    polyline.strokeColor = [UIColor redColor];
    polyline.strokeWidth = 5.f;
    polyline.map = mapView;


 failed:^(NSError *error) 
    NSLog(@"Can't reach the server")
];

【讨论】:

安装 Google Maps SDK 和 GoogleMapsDirection。【参考方案11】:

如您所知,从谷歌获取路线和路线不是免费的,去年谷歌改变了他们的 api 调用价格很多!所以它可能不适合每个人。因此,如果您拥有所有关键坐标并且只想将它们连接在一起,则可以使用以下内容。

- Swift 4 扩展

用坐标制作路径:

extension GMSMutablePath 
    convenience init(coordinates: [CLLocationCoordinate2D]) 
        self.init()
        for coordinate in coordinates 
            add(coordinate)
        
    

添加地图路径:

extension GMSMapView 
    func addPath(_ path: GMSPath, strokeColor: UIColor? = nil, strokeWidth: CGFloat? = nil, geodesic: Bool? = nil, spans: [GMSStyleSpan]? = nil) 
        let line = GMSPolyline(path: path)
        line.strokeColor = strokeColor ?? line.strokeColor
        line.strokeWidth = strokeWidth ?? line.strokeWidth
        line.geodesic = geodesic ?? line.geodesic
        line.spans = spans ?? line.spans
        line.map = self
    

用法:

let path = GMSMutablePath(coordinates: [<#Coordinates#>])
mapView.addPath(path)
注意:您可以使用那里的工具甚至 google 本身创建与 google 完全相同的行,将其存储在某个地方并根据需要将其提供给您的客户。

【讨论】:

【参考方案12】:

斯威夫特 5 它对我来说很好用

View will appear

self.drawMap(SourceCordinate: CLLocationCoordinate2D(latitude: lat, longitude: long), destinationcordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude))



func drawMap(SourceCordinate : CLLocationCoordinate2D, destinationcordinate :CLLocationCoordinate2D)
    
        self.mapView.clear()
        let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(SourceCordinate.latitude),\(SourceCordinate.longitude)&destination=\(destinationcordinate.latitude),\(destinationcordinate.longitude)&key=\(googleServiceKey)")
        print(str)
        Alamofire.request(str).responseJSON  (responseObject) -> Void in
            let resJson = JSON(responseObject.result.value!)
            print(resJson)
            let routes : NSArray = resJson["routes"].rawValue as! NSArray
            if(resJson["status"].rawString()! == "ZERO_RESULTS")
            else if(resJson["status"].rawString()! == "NOT_FOUND")
            else if routes.count == 0
            else
                let routes : NSArray = resJson["routes"].rawValue as! NSArray
//                let position = CLLocationCoordinate2D(latitude: SourceCordinate.latitude, longitude: SourceCordinate.longitude)
                let markerEnd = GMSMarker()
                markerEnd.position = CLLocationCoordinate2D(latitude: self.latitude, longitude: self.longitude)
                markerEnd.map = self.mapView
                let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
                let paths : NSArray = pathv.value(forKey: "points") as! NSArray
                let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
                let polyLine = GMSPolyline(path: newPath)
                polyLine.strokeWidth = 5
                polyLine.strokeColor =  .black
                let ThemeOrange = GMSStrokeStyle.solidColor( .blue)
                let OrangeToBlue = GMSStrokeStyle.gradient(from:  .blue, to:  .blue)
                polyLine.spans = [GMSStyleSpan(style: ThemeOrange),
                                  GMSStyleSpan(style: ThemeOrange),
                                  GMSStyleSpan(style: OrangeToBlue)]
                polyLine.map = self.mapView

            
        
    

【讨论】:

以上是关于在iOS中的GMSMapView上绘制两地之间的路线的主要内容,如果未能解决你的问题,请参考以下文章

在 GMSMapView 上显示折线的开始和结束标记

自定义 UIView 上的 Google 地图 GMSMapView

使用 Google Maps iOS 绘制路线方向

在 GMSMapView 上确定适当的缩放级别以适合所有需要的位置?

在地图上如何算出两地之间距离

从 GMSMapView 中删除所有 GMSMarker?