swift - 如何使用 swiftUI View 在启动时将 Google map 相机聚焦在用户当前位置

标签 swift cllocationmanager swiftui google-maps-sdk-ios xcode11

我正在尝试制作一个使用 Google map 的应用,并在打开应用时重点关注用户的位置。

现在我已经初始化了 map ,按下 GoogleMaps 固有的“myLocation”按钮后,我能够聚焦于用户位置,但 map 的相机始终聚焦于指定位置,而不是用户位置。

我使用了这两个教程来达到我现在的水平: -https://developers.google.com/maps/documentation/ios-sdk/start -https://www.raywenderlich.com/197-google-maps-ios-sdk-tutorial-getting-started

搜索 Google 和此处后,似乎我需要利用 CLLocationManager() 来获取用户的设备坐标,然后以某种方式使用它?我认为我关于 CLLocationManager() 的代码可能放置在错误的文件中或使用不正确,但我没有收到任何错误。

我的代码是这样工作的:SceneDelegate.swift 将我的 LandmarkList.swift 设置为 rootViewController。然后 LandmarkList 调用 GoogMapView.swift 来显示 Google map 的实例。

SceneDelegate.swift:

我认为我在这里使用 locationManager 可能是错误的?

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:

注意:下面的打印语句仅返回“用户位置未知”

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
    }
}

同样,我认为 SceneDelegate.swift 中有关 locationManager 的代码将使 GoogleMaps 相机实例在启动时聚焦于用户位置,但事实并非如此。

有人知道我做错了什么吗?

最佳答案

使用此处的评论和 StackOverflow 上的其他评论,我提出了这个解决方案:

//
//  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>) {

    }
}



关于swift - 如何使用 swiftUI View 在启动时将 Google map 相机聚焦在用户当前位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58346305/

相关文章:

ios - 如何从解析服务器检索数据?

ios - 如何在 Objective C 和 swift Viewcontroller 中使用委托(delegate)

ios - 在 Xcode/Swift 中导出 TableView 数据

macos - CLLocationManager 可以在 MAC 中与外部 GPS 配合使用吗

ios - SwiftUI:如何以编程方式更改 rootview Controller

swift - 我正在制作简单的Note应用程序。但是,当我运行该应用程序时,它无法处理此错误消息线程1:在AppDelegate类中发出SIGABRT信号

ios - CoreLocation 在一定时间后停止在后台工作

ios - 位置管理器 :didFailWithError: not called if user Location Services are off

ios - 将 View 作为参数添加到自定义 ViewModifier

SwiftUI - 文本嵌入到 ScrollView 后被截断