How to focus Google Maps camera on user's current location at startup using swiftUI views

google map move camera
ios google maps zoom to fit markers
how to set zoom level in google map in android
newlatlngbounds
set zoom level google maps ios
android google maps zoom to fit markers
google maps swift
google maps swiftui

I'm trying to make an app that uses Google Maps and focuses on the user's location when the app is opened.

Right now I have the map initializing and im able to focus on the users location after pressing the 'myLocation' button that is inherent to GoogleMaps, BUT the map's camera keeps focusing to a specified location and not the users location.

I used these 2 tutorials to get to where I'm at now: - https://developers.google.com/maps/documentation/ios-sdk/start - https://www.raywenderlich.com/197-google-maps-ios-sdk-tutorial-getting-started

After searching Google and here, it seems like I need to utilize CLLocationManager() to get the user's device coordinates and then use that somehow? Im think my code regarding CLLocationManager() may be placed in the wrong file or is used incorrectly, but im not getting any errors.

My code works like this: SceneDelegate.swift sets my LandmarkList.swift as the rootViewController. Then the LandmarkList calls GoogMapView.swift to display the instance of Google maps.

SceneDelegate.swift:

I think my usage of locationManager here may be wrong?

import UIKit
import SwiftUI
import GoogleMaps
import GooglePlaces
import CoreLocation



class SceneDelegate: UIResponder, UIWindowSceneDelegate, CLLocationManagerDelegate {


    var window: UIWindow?
    private let locationManager = CLLocationManager()


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Use a UIHostingController as window root view controller
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: LandmarkList())
            self.window = window
            window.makeKeyAndVisible()
        }

        locationManager.requestAlwaysAuthorization()

        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestWhenInUseAuthorization()
        }

    }
}

LandmarkList.swift:

import SwiftUI

struct LandmarkList: View {

    @State private var searchText = ""
    @State private var locationText = ""


    var body: some View {


            ZStack(alignment: Alignment.top) {
                GoogMapView()
                    .frame(height: 750)


                SlideOverCard {
                    VStack(alignment: .leading) {
                        List(landmarkData) { landmark in
                            NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                                LandmarkRow(landmark: landmark)
                            }
                        }

                    }
                        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.topLeading)
                    }
        }
    }
}

GoogMapView.swift:

Note: The print statement below only returns 'User's location is unknown'

import SwiftUI
import UIKit
import GoogleMaps
import GooglePlaces
import CoreLocation


struct GoogMapView : UIViewRepresentable {

        let marker : GMSMarker = GMSMarker()

        //Creates a `UIView` instance to be presented.
        func makeUIView(context: 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")
            }

            return mapView
        }

//        Updates the presented `UIView` (and coordinator) to the latestconfiguration.
    func updateUIView(_ mapView: GMSMapView, context: 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
    }
}

Again, I think my code regarding locationManager in SceneDelegate.swift would make the instance of GoogleMaps camera focus on the users location at startup, but it doesnt.

Anyone know what im doing wrong?

You can implement this by "pretending" your View is a ViewController. Try setting GoogleMapView as the delegate, instead. Then put your initialization code in makeUIView and then conform to the protocol:

struct GoogMapView : CLLocationManagerDelegate {

private let locationManager = CLLocationManager()

  func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

    guard status == .authorizedWhenInUse else {
      return
    }

    locationManager.startUpdatingLocation()


    mapView.isMyLocationEnabled = true
    mapView.settings.myLocationButton = true
  }


  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.first else {
      return
    }


    mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)


    locationManager.stopUpdatingLocation()
  }
}

Above taken from https://www.raywenderlich.com/197-google-maps-ios-sdk-tutorial-getting-started.

Camera and View | Maps SDK for Android, Released today, the latest version of the Google Maps Android API includes more developer requested features: you can now track camera  Google Maps updated to work with Camera, offer smart recommendations. At Google I/O, Google explained how it's using AI and "VPS" to offer users a richer, more personalized Google Maps experience.

Using comments here and others on StackOverflow, I made this solution:

//
//  GoogMapView.swift
//  Landmarks
//
//  Created by Zahr Lyttle on 10/14/19.
//  Copyright © 2019 Apple. All rights reserved.
//

import SwiftUI
import UIKit
import GoogleMaps
import GooglePlaces
import CoreLocation
import Foundation



struct GoogMapView: View {
    var body: some View {
        GoogMapControllerRepresentable()
    }
}


class GoogMapController: UIViewController, CLLocationManagerDelegate {
    var locationManager = CLLocationManager()
    var mapView: GMSMapView!
    let defaultLocation = CLLocation(latitude: 42.361145, longitude: -71.057083)
    var zoomLevel: Float = 15.0
    let marker : GMSMarker = GMSMarker()


    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.distanceFilter = 50
        locationManager.startUpdatingLocation()
        locationManager.delegate = self

        let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude, longitude: defaultLocation.coordinate.longitude, zoom: zoomLevel)
        mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.isMyLocationEnabled = true
        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")
//        }

        marker.position = CLLocationCoordinate2D(latitude: 42.361145, longitude: -71.057083)
        marker.title = "Boston"
        marker.snippet = "USA"
        marker.map = mapView

        // Add the map to the view, hide it until we've got a location update.
        view.addSubview(mapView)
//        mapView.isHidden = true

    }

    // Handle incoming location events.
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
      let location: CLLocation = locations.last!
      print("Location: \(location)")

      let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: zoomLevel)

      if mapView.isHidden {
        mapView.isHidden = false
        mapView.camera = camera
      } else {
        mapView.animate(to: camera)
      }

    }

    // Handle authorization for the location manager.
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
      switch status {
      case .restricted:
        print("Location access was restricted.")
      case .denied:
        print("User denied access to location.")
        // Display the map using the default location.
        mapView.isHidden = false
      case .notDetermined:
        print("Location status not determined.")
      case .authorizedAlways: fallthrough
      case .authorizedWhenInUse:
        print("Location status is OK.")
      }
    }

    // Handle location manager errors.
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
      locationManager.stopUpdatingLocation()
      print("Error: \(error)")
    }

}


struct GoogMapControllerRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<GMControllerRepresentable>) -> GMController {
        return GMController()
    }

    func updateUIViewController(_ uiViewController: GMController, context: UIViewControllerRepresentableContext<GMControllerRepresentable>) {

    }
}



Camera and View | Maps SDK for iOS, Expressive and flexible: Quickly ship features with a focus on native end-user 1 billion monthly active users: Scale confidently, backed by Google Maps'  Find local businesses, view maps and get driving directions in Google Maps. When you have eliminated the JavaScript , whatever remains must be an empty page. Enable JavaScript to see Google Maps.

Keep users focused on what's important with the latest Google Maps , How do I set the zoom level to show all the markers on Google Maps? Google Maps allows a neat little trick that allows users to take down a section of the maps data offline and store it locally on their devices. Once this data is stored offline, you do not need

Adding Google Maps to a Flutter app, Please watch the teach video to know how to use it. When you take a picture, this application will paste the Google map, address, weather and date to picture. The piece of code to pay attention here is the onMapCreated event, which I handle by obtaining the reference to the Google Map’s controller, and since the map is ready to be manipulated when

Google Maps API V3: Center and Zoom to fit all markers on Google , in audio output · Managing audio focus · The Google Assistant and media apps The Google Maps Android API allows you to include maps and Add markers onto the map to indicate special points of interest for your users. control the zoom and orientation (tilt and bearing) of the Street View camera,  Google Maps users contribute more than 20 million pieces of information every day–that’s more than 200 contributions every second. In addition to the updates we make from what people tell us, we’re making countless updates uncovered through other means like the imagery and machine learning efforts we’ve shared with you in the recent

Set up and connect 360 cameras, Tip: Point your phone camera at buildings and signs across the street instead of trees and people. Once Maps knows where you are, you'll see directions through​  This map was created by a user. Learn how to create your own.

Comments
  • I pasted your code into GoogMapView.swift before adding my makeUIView and updateUIView functions and keep getting the error 'Non-class type 'GoogMapView' cannot conform to class protocol 'CLLocationManagerDelegate'. Did you not get an error in Xcode? If i change from a struct to a class, that gets rid of the error but then i dont think ill be able to call GoogMapView() in LandmarkList.swift.