【问题标题】:How to make form sheet appear after Google Maps marker infoWindow is tapped in iOS?在 iOS 中点击 Google Maps 标记 infoWindow 后如何使表单显示?
【发布时间】:2023-03-27 01:35:01
【问题描述】:

我目前正在使用 SwiftUI 和 Google 地图构建一个应用程序。我正在尝试在点击 Google 地图标记的 infoWindow 后显示表单,但我无法使其正常工作。

在我的应用程序的其他部分,我使用以下方法显示工作表: Example method here

我尝试使用与上述相同的方法在点击标记的 infoWindow 后显示工作表,但在函数内执行此操作时遇到问题。下面我的代码 sn-ps 提供了更多详细信息。

-

下面是我的 GMView.swift 文件的精简版,它控制着我的 Google 地图实例。 (我的文件看起来与典型的 Swift + Google 地图集成不同,因为我使用的是 SwiftUI)。 您会注意到文件的 3 个主要部分:1. 视图、2. GMController 类和3. GMControllerRepresentable 结构:

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



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


class GoogMapController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
    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()

//        Control location data
        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()
        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.distanceFilter = 50
            locationManager.startUpdatingLocation()
        }


        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


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


//        view.addSubview(mapView)
        mapView.delegate = self
        self.view = mapView

    }

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

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

    }
}

这是我在上面的 GMView.swift 文件中添加到 GMController 类的函数,Google 的文档说在点击标记的 infoWindow 时使用它来处理:

// Function to handle when a marker's infowindow is tapped
    func mapView(_ mapView: GMSMapView, didTapInfoWindowOf didTapInfoWindowOfMarker: GMSMarker) {
        print("You tapped a marker's infowindow!")
//        This is where i need to get the view to appear as a modal, and my attempt below
        let venueD2 = UIHostingController(rootView: VenueDetail2())
        venueD2.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - 48)
        self.view.addSubview(venueD2.view)
        return
    }

我上面的函数当前在点击信息窗口时显示一个视图,但它只是出现在我的谷歌地图视图上,所以我没有看到动画,也不能像典型的 iOS 表单一样关闭视图。

有谁知道如何在 SwiftUI 中点击 Google 地图标记信息窗口后显示工作表,而不仅仅是将其添加为子视图?

【问题讨论】:

    标签: ios google-maps swiftui google-maps-sdk-ios gmsmapview


    【解决方案1】:

    您好,要从 struct View 与 UIViewController 交互,您需要绑定一个变量。首先,我们声明 @Binding var isClicked : Bool,如果您需要将更多参数传递给 struct,您需要使用声明 @Binding 声明它。 UIViewController 中的任何错误都会显示isClicked Property 'self.isClicked' 未初始化以修复我们声明的问题:

    @Binding var isClicked
    init(isClicked: Binding<Bool>) {
            _isClicked = isClicked
            super.init(nibName: nil, bundle: nil) 
        }
    

    UIViewController 的指定初始化程序是 initWithNibName:bundle:。您应该改为调用它。如果您没有 nib,请为 nibName 传入 nil(bundle 也是可选的)。 现在我们已经完成了UIViewController 的所有设置,我们移动到UIViewControllerRepresentable:与我们最初所做的一样,我们需要声明@Binding var isClicked 因为viewController 将在初始化时请求一个新参数,所以我们将有类似的东西这个:

    @Binding var isClicked: Bool
    func makeUIViewController(context: UIViewControllerRepresentableContext<GMControllerRepresentable>) -> GMController {
            return GMController(isClicked: $isClicked)
        }
    

    在结构视图中:

    @State var isClicked: Bool = false
    var body: some View {
            GoogMapControllerRepresentable(isClicked: $isClicked)
    .sheet(isPresented: $isShown) { () -> View in
                <#code#>
            }
        }
    

    还有一件事我们只需要像这样在标记点击时切换这个变量:

    func mapView(_ mapView: GMSMapView, didTapInfoWindowOf didTapInfoWindowOfMarker: GMSMarker) {
            print("You tapped a marker's infowindow!")
    //        This is where i need to get the view to appear as a modal, and my attempt below
           self.isClicked.toggle()
    // if you want to pass more parameters you can set them from here like self.info = //mapView.coordinate <- Example
            return
        }
    

    【讨论】:

    • 你是个好人。这很有效,您的回答帮助我更好地理解了我的设置。谢谢!
    猜你喜欢
    • 2020-02-17
    • 1970-01-01
    • 2017-10-23
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2013-01-25
    • 1970-01-01
    相关资源
    最近更新 更多