Show Path on GoogleMaps in Swift4

2019-07-10 05:06发布

My question is I want to draw the time between two points and my both location are coming from different controllers

for my first Location :- 
  extension HomeViewController: PickupLocationDelegate {
func didSelectLocation(place: GooglePlaceModel?) {
    guard let place = place else {return}
    enter_Location_TF.text = place.name
    customDirectionViewTwo.isHidden = false
    direction_Button.isHidden = true
    location_Button.setImage(UIImage(named: "directionPoint")?.withRenderingMode(.alwaysOriginal), for: .normal)

    pickupMarkers.forEach { (marker) in
        marker.map = nil
    }
    let position = CLLocationCoordinate2D(latitude: place.latitude , longitude: place.longitude)
    print(position)
    let path = GMSMutablePath()
    path.add(CLLocationCoordinate2D(latitude: place.latitude, longitude: place.longitude))
    let marker = GMSMarker()
    marker.position = position
    marker.map = mapView
    mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
    pickupMarkers.append(marker)

}
}// My second location:-
 extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
    guard let location = location else {return}
    dropLocationLbl?.text = location.name


    let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
    print(position)
    let marker = GMSMarker(position: position)
    marker.icon = #imageLiteral(resourceName: "icon-drop-location")
    marker.map = mapView

    mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
    pickupMarkers.append(marker)
    let path = GMSMutablePath()
    path.add(CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
    pickupMarkers.forEach { (marker) in
        path.add(marker.position)
    }
    let bounds = GMSCoordinateBounds(path: path)
    mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}

marker are showing correctly but the path is not showing. I used the GMSMutable path to draw the line between location but this is not working properly. Any help?

1条回答
Melony?
2楼-- · 2019-07-10 05:31

Preconditions

You need to get a Google directions api Key following this link How to get a Google Directions API key and you also need to add this line

GMSPlacesClient.provideAPIKey("Your API KEY")

in your AppDelegate didFinishLaunchingWithOptions method

Now our issue

To find a path you need to use a method like this one, using googleapis.directions request, passing two CLLocationCoordinate2D then in the closure you will get an array of CLLocationCoordinate2D which are the waypoints of your path

public func getWaypointsAsArrayOfCoordinates(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D, mode:String? = "walking", lang:String? = "en", finishedClosure:@escaping (([CLLocationCoordinate2D])->Void)){

        var resultedArray:[CLLocationCoordinate2D] = []

        let urlWithParams = "https://maps.googleapis.com/maps/api/directions/json" + self.customEncodedParameters(parametersDict: ["origin":"\(startLocation.latitude),\(startLocation.longitude)", "destination": "\(endLocation.latitude),\(endLocation.longitude)", "mode": mode!, "key":googleDirectionsApiKey, "language" : lang!])

        var urlRequest = URLRequest(url: URL(string: urlWithParams)!)
        urlRequest.httpMethod = "GET"

        URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in

            if let _ = error {
            } else {
                do {
                    if  let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
                        let status = jsonData["status"] as! String
                        if(status == "OK") {

                            for routeDict in jsonData["routes"] as! Array<Dictionary<String, AnyObject>>
                            {
                                let legs = routeDict["legs"] as! Array<Dictionary<String, AnyObject>>
                                for leg in legs
                                {
                                    let steps = leg["steps"] as! Array<Dictionary<String, AnyObject>>
                                    for (index,step) in steps.enumerated(){
                                        let start = step["start_location"] as! Dictionary<String,Any>
                                        let end = step["end_location"] as! Dictionary<String,Any>
                                        resultedArray.append(CLLocationCoordinate2D(latitude: start["lat"] as! CLLocationDegrees, longitude: start["lng"] as! CLLocationDegrees))
                                        if(index == steps.count - 1) {
                                            resultedArray.append(CLLocationCoordinate2D(latitude: end["lat"] as! CLLocationDegrees, longitude: end["lng"] as! CLLocationDegrees))
                                        }
                                    }
                                }
                            }
                            finishedClosure(resultedArray)
                        }
                        else {
                            print("not found")
                            finishedClosure([])
                        }
                    }
                } catch {
                    print(error)
                    finishedClosure([])
                }
            }

            }.resume()

    }

Edit (Added missing function)

private func customEncodedParameters(parametersDict:[String:String]) ->String
    {
        let charactersAllowed = CharacterSet.urlQueryAllowed
        var returnStr = ""
        for key in parametersDict.keys {
            if(returnStr.count == 0)
            {
                returnStr += "?"
                returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
                returnStr += "="
                returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
            }else{
                returnStr += "&"
                returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
                returnStr += "="
                returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
            }
        }
        return returnStr
    }

Then you can use it in your code like this

extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
    guard let location = location else {return}
    dropLocationLbl?.text = location.name


    let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
    print(position)
    let marker = GMSMarker(position: position)
    marker.icon = #imageLiteral(resourceName: "icon-drop-location")
    marker.map = mapView

    mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
    pickupMarkers.append(marker)
    self.getWaypointsAsArrayOfCoordinates(startLocation: pickupMarkers.first.position , endLocation: pickupMarkers.last.position) { [weak self] (arrayOfCoordinates) in

        DispatchQueue.main.async {
            let path = GMSMutablePath()

            for coordinate in arrayOfCoordinates {
                path.add(coordinate)
            }

            let polyline = GMSPolyline(path: path)
            polyline.strokeWidth = 2
            polyline.strokeColor = UIColor.red
            polyline.map = self?.mapView

            let bounds = GMSCoordinateBounds(path: path)
            self?.mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
        }
    }
}
}
查看更多
登录 后发表回答