当用户在 SwiftUI 中触摸 GoogleMaps 的标记时如何更改 UI 状态?

Posted

技术标签:

【中文标题】当用户在 SwiftUI 中触摸 GoogleMaps 的标记时如何更改 UI 状态?【英文标题】:How to change UI state when user touch GoogleMaps' Marker in SwiftUI? 【发布时间】:2020-09-03 07:24:30 【问题描述】:

这个问题是关于 SwiftUI 的。

我正在尝试显示地图并允许用户触摸任何可用的标记。发生这种情况时,我希望更改视图上的文本,以反映该用户的操作。

经过大量搜索,我认为解决方案可能接近 Observable 协议,但我就是想不出正确的方法。这是我的代码:


struct Home: View 

    // Here's the attribute I want to be changed when user touches the marker
    var selectedMarker: GMSMarker?

    var body: some View 

            VStack(spacing: 0) 

                // Condition to be applied when user touches the marker                                
                if (selectedMarker == nil)
                    Text("No marker selected").padding()
                else
                    Text("Now, there's a marker selected").padding()
                

                GoogleMapsHome()

        
        .navigationBarBackButtonHidden(true)
        .navigationBarTitle(Text("Marker question"), displayMode: .inline)

    



struct Home_Previews: PreviewProvider 
    static var previews: some View 
        Home()
    


这是 GoogleMaps 的定义:

struct GoogleMapsHome: UIViewRepresentable 

    private let zoom: Float = 18

    // Just for didactic purposes. Later, I'm going to use LocationManager
    let lat: Double = -15.6692660716233
    let lng: Double = -47.83980712156295

    func makeUIView(context: Self.Context) -> GMSMapView 

        let camera = GMSCameraPosition.camera(
            withLatitude: lat,
            longitude: lng,
            zoom: zoom)

        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)

        mapView.mapType = .hybrid

        mapView.delegate = context.coordinator

        return mapView

    

    func updateUIView(_ mapView: GMSMapView, context: Context) 

        mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))

        let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
        let marker = GMSMarker(position: position)

        marker.title = "You"

        marker.map = mapView

    

    func makeCoordinator() -> Coordinator 
       Coordinator(owner: self)
    

    class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject 

        let owner: GoogleMapsHome       // access to owner view members,

        init(owner: GoogleMapsHome) 
         self.owner = owner
        

        @Published var selectedMarker: GMSMarker? 
            willSet  objectWillChange.send() 
        

        func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool 

            print("A marker has been touched by the user")

            self.selectedMarker = marker

            return true

        

    


我希望有人可以帮助我,以后,这个问题对任何有同样需要的人都有用。

最好的问候!

【问题讨论】:

【参考方案1】:

过了一会儿,我找到了解决它的方法。

其中的关键字是“协调器”和“绑定”。

当然,我不确定这是正确的方法还是最好的方法,但至少它奏效了。


import Foundation
import SwiftUI
import GoogleMaps

struct Home: View 

    @State var selectedMarker: GMSMarker?

    var body: some View 

            VStack(spacing: 0) 

                if (selectedMarker == nil)
                    Text("No marker selected").padding()
                else
                    Text("There's a marker selected").padding()
                

                GoogleMapsHome(selectedMarker: self.$selectedMarker)

        
        .navigationBarBackButtonHidden(true)
        .navigationBarTitle(Text("Map Test"), displayMode: .inline)

    



struct Home_Previews: PreviewProvider 
    static var previews: some View 
        Home()
    


struct GoogleMapsHome: UIViewRepresentable 

    private let zoom: Float = 18

    let lat: Double = -15.6692660716233
    let lng: Double = -47.83980712156295

    @Binding var selectedMarker: GMSMarker?

    func makeCoordinator() -> Coordinator 
        return Coordinator(
            owner: self,
            selectedMarker: $selectedMarker)
    

    func makeUIView(context: Self.Context) -> GMSMapView 

        let camera = GMSCameraPosition.camera(
            withLatitude: lat,
            longitude: lng,
            zoom: zoom)

        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)

        mapView.mapType = .hybrid

        mapView.delegate = context.coordinator

        return mapView

    

    func updateUIView(_ mapView: GMSMapView, context: Context) 

        mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))

        let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
        let marker = GMSMarker(position: position)

        marker.title = "You"

        marker.map = mapView

    


    class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject 

        let owner: GoogleMapsHome       // access to owner view members,

        @Binding var selectedMarker: GMSMarker?

        init(
            owner: GoogleMapsHome,
            selectedMarker: Binding<GMSMarker?>
        ) 

            self.owner = owner

            _selectedMarker = selectedMarker

        

        func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool 

            print("A marker has been touched")

            self.selectedMarker = marker

            return true

        

    


【讨论】:

以上是关于当用户在 SwiftUI 中触摸 GoogleMaps 的标记时如何更改 UI 状态?的主要内容,如果未能解决你的问题,请参考以下文章

ios14 Xcode 12 - 触摸 SwiftUI 对象时精灵不显示,但触摸 SKScene 时工作

如何知道用户在 SwiftUI 中的日期选择器中触摸了哪一天

*当前*正在触摸哪个 SwiftUI 节点?

在用户想要画线时获取 CGPoint 数组

在swiftui中按钮的触摸动作播放音频

SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标