0

I am integrating Google Places in my SwiftUI app. I have searched a lot but didn't get any proper result for SwiftUI. I tried the solution in the comments of place autocomplete but didn't get my desired work.

I want:

desired

I tried the following solution which helped me a lot to get my desired work but there is an issue with this is that for every location I searched, I got that location but the latitude and longitude always comes -180 for all locations.

Here is my code for View:

import SwiftUI
import GooglePlaces

struct MyGooglePlace: View {
    
    @State var openPlacePicker = false
    @State var address = ""
    
    var body: some View {
        
        VStack {
            
            Text(address)
            
            Button {
                
                openPlacePicker.toggle()
            } label: {
                
                Text("open place picker")
            }
      
        }.sheet(isPresented: $openPlacePicker) {
            PlacePicker(address: $address)
        }
    }
}

And the PlacePicker is:

import Foundation
import UIKit
import SwiftUI
import GooglePlaces


struct PlacePicker: UIViewControllerRepresentable {
    
    func makeCoordinator() -> GooglePlacesCoordinator {
        GooglePlacesCoordinator(self)
    }
    @Environment(\.presentationMode) var presentationMode
    @Binding var address: String

    func makeUIViewController(context: UIViewControllerRepresentableContext<PlacePicker>) -> GMSAutocompleteViewController {

        let autocompleteController = GMSAutocompleteViewController()
        autocompleteController.delegate = context.coordinator
        

        let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
                                                  UInt(GMSPlaceField.placeID.rawValue))
        autocompleteController.placeFields = fields

        let filter = GMSAutocompleteFilter()
        filter.type = .address
        autocompleteController.autocompleteFilter = filter
        return autocompleteController
    }

    func updateUIViewController(_ uiViewController: GMSAutocompleteViewController, context: UIViewControllerRepresentableContext<PlacePicker>) {
    }

    class GooglePlacesCoordinator: NSObject, UINavigationControllerDelegate, GMSAutocompleteViewControllerDelegate {

        var parent: PlacePicker

        init(_ parent: PlacePicker) {
            self.parent = parent
        }

        func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
            DispatchQueue.main.async {
                print(place.description.description as Any)
                self.parent.address =  place.name!
                self.parent.presentationMode.wrappedValue.dismiss()
                print("latitude: \(place.coordinate.latitude)")
                print("longitude: \(place.coordinate.longitude)")
            }
        }

        func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
            print("Error: ", error.localizedDescription)
        }

        func wasCancelled(_ viewController: GMSAutocompleteViewController) {
            parent.presentationMode.wrappedValue.dismiss()
        }

    }
}

If I searched for some place in USA, it gives the coordinates -180, -180, and if I search for some location in Pakistan, it still gives -180, -180 coordinates.

Does anyone knows how to get the exact coordinates of the searched location?

Taimoor Arif
  • 750
  • 3
  • 19
  • 1
    Please check this: https://stackoverflow.com/questions/55978576/gmsplace-returns-invalid-coordinate-180-180-but-name-and-place-id-are-corr – Kishan Bhatiya Jun 16 '22 at 08:07

1 Answers1

2

Here I am posting a complete solution.

import SwiftUI
import GooglePlaces

struct PlacesViewControllerBridge: UIViewControllerRepresentable {
    
    var onPlaceSelected: (GMSPlace) -> ()
    //var selectedPlaceByFilter: GMSPlace
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<PlacesViewControllerBridge>) -> GMSAutocompleteViewController {
     let uiViewControllerPlaces = GMSAutocompleteViewController()
        uiViewControllerPlaces.delegate = context.coordinator
        let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
                                                  UInt(GMSPlaceField.placeID.rawValue))
        uiViewControllerPlaces.placeFields = fields
        return uiViewControllerPlaces
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    
    }
    
    func makeCoordinator() -> PlacesViewAutoCompleteCoordinator {
        return PlacesViewAutoCompleteCoordinator(placesViewControllerBridge: self)
    }
    
    final class PlacesViewAutoCompleteCoordinator: NSObject, GMSAutocompleteViewControllerDelegate {
        var placesViewControllerBridge: PlacesViewControllerBridge
        
        init(placesViewControllerBridge: PlacesViewControllerBridge) {
            self.placesViewControllerBridge = placesViewControllerBridge
        }
        
        func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace)
        {
            print("Place name: \(place.name ?? "Default Place")")
            print("Place ID: \(place.placeID ?? "Default PlaceID")")
            print("Place attributions: \(String(describing: place.attributions))")
            viewController.dismiss(animated: true)
            self.placesViewControllerBridge.onPlaceSelected(place)
        }
        
        func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error)
        {
            print("Error: ", error.localizedDescription)
        }
        
        func wasCancelled(_ viewController: GMSAutocompleteViewController) {
            print("Place prediction window cancelled")
            viewController.dismiss(animated: true)
        }
        
        func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }
        
        func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
        }
        
    }
}

Below is the usage in the custom text field.

CustomTextFieldWithEditing(
                            placeHolderText: "Enter your Location",
                            text: $tempLocation,
                            errorMessage: $isCsLocationMessage,
                            isError: $isCsLocationError,
                            isSecure: false,
                            action: {
                                isPresent = true
                            }
                        ).textFieldStyle(CustomTextFieldStyle(icon: Image(systemName: "location.circle.fill")))
                            .sheet(isPresented: $isPresent) {
                                PlacesViewControllerBridge(onPlaceSelected: {
                                    place in
                                    tempLocation =  place.name ?? "Please select your location"
                                    selectedGMSPlace = place
                                    isCsLocationError = false
                                })
                            }
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103