Рисование маршрута между двумя местами в GMSMapView в iOS

Я разрабатываю приложение для iOS. В этом приложении у меня есть 2 поля From и To. Я ввел адрес с помощью Google Auto Complete API, а также могу получить широту и долготу для двух мест и показать маркеры на GMSMapView.

Теперь я хочу нарисовать маршрут между этими двумя местами. Я нашел решение, когда мы используем MKMapView. Но я не смог найти решение для GMSMapView. пожалуйста, помогите мне нарисовать маршрут между этими двумя точками в GMSMapView.

Если возможно, пожалуйста, дайте мне несколько важных ссылок для этого.

Спасибо.


person Suresh Peddisetti    schedule 21.03.2014    source источник


Ответы (12)


Я написал следующий код, который должен вам помочь:

- (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];
}
person Tarek    schedule 27.01.2016
comment
Можем ли мы получить версию Swift для этого? - person Bista; 07.06.2016
comment
@ Tarek, будьте осторожны ==› Google Maps iOA SDK требует, чтобы все события рисования выполнялись в основном потоке. Итак, для вашего второго метода вы должны поместить весь код установки вашего производителя в замыкание dispatch_get_main_queue(). В противном случае будьте готовы разбить ваше сладкое приложение. - person Ravi; 01.03.2017
comment
@Monusingh, ты абсолютно прав! Я только что изменил код, чтобы обработчик завершения выполнялся в основном потоке. Спасибо! - person Tarek; 02.03.2017
comment
Здравствуйте, у меня возникает сбой в строке polyline = [GMSPolyline polylineWithPath:path]; раздела Все вызовы Google Maps SDK для iOS должны выполняться из потока пользовательского интерфейса - person Mukesh; 20.04.2017
comment
Я преобразовал этот код в быстрый, но здесь возникает ошибка, если завершениеHandler {completeHandler(nil)}. Ошибка: «(GMSPolyline?) -> Void» не преобразуется в «Bool» - person iOS; 04.09.2018

Чтобы 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
    }

Примечание. В URL-адрес необходимо указать ключ API googleDirection.

person Hardik Thakkar    schedule 11.07.2017
comment
спасибо, очень помогли мне с небольшими корректировками! - person Mattk90; 28.09.2017
comment
Эй, я использую ваш код, но не получаю результата. Требуется ли какой-либо файл json? - person Khushbu Desai; 05.03.2018
comment
вам нужно использовать правильный ключ googleAPI и необходимо включить функцию googleDirection также для этого ключа. - person Hardik Thakkar; 06.03.2018

Если кто-то ищет Swift 3.0 для ответа @Tarek, вы можете использовать это. Это также использует 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
      }
    }
  }
person Christian Abella    schedule 15.12.2016

Вот быстрый перевод ответа Джонни Кумара.

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
person Pomme2Poule    schedule 07.06.2016
comment
это рисует прямую линию :( - person DeyaEldeen; 18.08.2016

- 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
person Sourabh Sharma    schedule 27.09.2016

Сделайте URL-запрос к Google Directions API, и когда вы получите файл JSON, выполните все шаги и декодируйте объекты точек.

person WWJD    schedule 21.03.2014

Я сделал это с помощью AlamoFire и SwiftyJson в xCode 8.3.3 и Swift 3.1. Поместите рисунок пути в функцию, которой нужны только два параметра

пример источника строки "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
                    }
                }
            }
        }
    }
}
person Charley57    schedule 14.07.2017

Привет. Вы можете использовать «LRouteController», это лучший способ показать маршрут между двумя точками, например:

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

Попробуйте, надеюсь, это решит вашу проблему.

person Devil    schedule 29.10.2015

DirectionResponse от Google Directions APIЖурналы NSLog полезны, чтобы увидеть, над чем вы работаете. с участием.

[[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")
}];
person Nil Rathod    schedule 15.09.2016
comment
установка Google Maps SDK и GoogleMapsDirection. - person Nil Rathod; 15.09.2016

Как вы знаете, получение указаний и маршрутов от Google является НЕ БЕСПЛАТНЫМ, и в прошлом году Google сильно изменил свои цены на вызовы API! Так что это может подойти не всем. Итак, если у вас есть все ключевые координаты и вы просто хотите соединить их вместе, вы можете использовать следующее.

- Свифт 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, сохранить ее где-нибудь и предоставить своему клиенту по мере необходимости.
person Mojtaba Hosseini    schedule 18.02.2019

Swift 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

            }
        }
    }
person Srinivasan_iOS    schedule 09.06.2020

person    schedule
comment
Спасибо за ваш ответ. Это решило мою проблему. Это нормально для небольшого расстояния. На дальние расстояния нужно время. есть ли решение для этого? - person Suresh Peddisetti; 22.03.2014
comment
Это создает линию от места до места. Я хочу, чтобы он создал зигзагообразный путь с анимацией. Как это возможно? - person Soumya Ranjan; 11.09.2014
comment
вы должны указать все точки либо в цикле for, либо с помощью функции. Или, возможно, вы не вставили внутренние точки. - person johny kumar; 12.09.2014
comment
получил ошибку: ld: library not found for -lPods-Google-Maps-iOS-SDK clang: error: linker command failed with exit code 1 (use -v to see invocation) - person Monika Patel; 10.09.2015
comment
напрямую загрузить библиотеку и добавить в свой проект - person johny kumar; 10.09.2015
comment
используя этот код .. нарисуйте путь... путь будет отображаться в виде прямой линии... не будет отображаться на дорожной карте - person Monika Patel; 10.09.2015
comment
вам нужно добавить все координаты в массив для маршрута. - person johny kumar; 10.09.2015
comment
@SundeepSaluja проверьте этот ответ, чтобы получить json из указаний Google: stackoverflow.com/a/29847639/3134130 - person johny kumar; 02.12.2015
comment
Спасибо. Это отлично работает для рисования линии между двумя координатами. - person Uma Madhavi; 21.01.2016
comment
это работает и для маршрута, если вы дадите весь массив latlngs спасибо за голосование - person johny kumar; 21.01.2016
comment
Вы можете использовать Google Maps Directions API developers.google.com/maps/documentation/directions/ начать . - person Ravi Kumar; 25.04.2019