Reputation: 269
Im still new to Xcode and SwiftUI so my apologies if this is simple to some people. Essentially, Im making an app that uses GoogleMaps iOS SDK and I'm trying to figure out how to focus the map's camera to a user's current location at startup.
Right now the way my code works is I have a main view which calls the GoogleMaps view and a couple of other views. The map initializes and the map's camera focuses on a set location i defined (Boston), drops a pin in a specific location (Boston), it displays my current location with a blue dot, and the camera focuses on my current location ONLY AFTER the myLocation button is tapped (which is inherent to Google Maps).
My main view that calls my Google maps view is here:
import SwiftUI
struct LandmarkList: View {
@State private var searchText = ""
@State private var locationText = ""
var body: some View {
NavigationView {
GoogMapView()
.frame(height: 750)
}
.edgesIgnoringSafeArea(.vertical)
.navigationBarItems(leading:
TextField("Current Location",text: self.$locationText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.multilineTextAlignment(.leading)
.frame(width: 375)
)
}
My Google maps view (i call it GoogMapView): UPDATED BASED ON COMMENTS & TUTORIAL BELOW:
import SwiftUI
//import MapKit
import UIKit
import GoogleMaps
import GooglePlaces
private let locationManager = CLLocationManager()
struct GoogMapView : UIViewRepresentable {
let marker : GMSMarker = GMSMarker()
//Creates a `UIView` instance to be presented.
func makeUIView(context: Self.Context) -> GMSMapView {
// Create a GMSCameraPosition
let camera = GMSCameraPosition.camera(withLatitude: 42.361145, longitude: -71.057083, zoom: 16.0)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.setMinZoom(14, maxZoom: 20)
mapView.settings.compassButton = true
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true
mapView.settings.scrollGestures = true
mapView.settings.zoomGestures = true
mapView.settings.rotateGestures = true
mapView.settings.tiltGestures = true
mapView.isIndoorEnabled = false
if let mylocation = mapView.myLocation {
print("User's location: \(mylocation)")
} else {
print("User's location is unknown")
}
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
return mapView
}
// Updates the presented `UIView` (and coordinator) to the latestconfiguration.
func updateUIView(_ mapView: GMSMapView, context: Self.Context) {
// Creates a marker in the center of the map.
marker.position = CLLocationCoordinate2D(latitude: 42.361145, longitude: -71.057083)
marker.title = "Boston"
marker.snippet = "USA"
marker.map = mapView
}
}
I thought i could grab mapView.myLocation and use that to manually focus the map camera on startup but that didnt work. You can see in the code above i try to print out the location but all i get back is 'User's location is unknown'. Also, now getting an error 'Cannot assign value of type 'GoogMapView' to type 'CLLocationManagerDelegate?'' where i type 'locationManager.delegate = self'.
Does anyone have an idea of the 'proper' way to have the map camera focus on a user's current location at startup?
Upvotes: 1
Views: 3260
Reputation: 3798
locationManager.requestWhenInUseAuthorization()
in another class. don't need locationManager.startUpdatingLocation
mapView.tag
property.struct GoogleMapView: UIViewRepresentable {
@State var coordinator = Coordinator()
func makeUIView(context _: Context) -> GMSMapView {
let view = GMSMapView(frame: .zero)
view.isMyLocationEnabled = true
view.animate(toZoom: 18)
view.addObserver(coordinator, forKeyPath: "myLocation", options: .new, context: nil)
return view
}
func updateUIView(_ uiView: GMSMapView, context _: UIViewRepresentableContext<GoogleMapView>) {}
func makeCoordinator() -> GoogleMapView.Coordinator {
return coordinator
}
static func dismantleUIView(_ uiView: GMSMapView, coordinator: GoogleMapView.Coordinator) {
uiView.removeObserver(coordinator, forKeyPath: "myLocation")
}
final class Coordinator: NSObject {
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
if let location = change?[.newKey] as? CLLocation, let mapView = object as? GMSMapView {
mapView.animate(toLocation: location.coordinate)
}
}
}
}
Upvotes: 0
Reputation: 26
I thought i could grab mapView.myLocation and use that to manually focus the map camera on startup but that didnt work. You can see in the code above i try to print out the location but all i get back is 'User's location is unknown'
It looks like mylocation does not contain any location coordinates. mapView.myLocation might not be what you think it is, perhaps it holds the user's device location and not the coordinate that you're passing to the GMSCameraPosition. According to the documentation
If My Location is enabled, reveals where the user location dot is being drawn.
So it's not the one you're passing to the camera
Does anyone have an idea of the 'proper' way to have the map camera focus on a user's current location at startup?
Have you created a locationManager somewhere and dealt with location permissions? If you have, you can catch the user's location inside a function called didUpdateLocations - it takes a couple of seconds or so to retrieve the user location upon startup. Once you get the location, you can do the panning the camera to the location.
Upvotes: 1