删除谷歌地图中的自定义信息窗口后如何取消选择 GMSMarker

Posted

技术标签:

【中文标题】删除谷歌地图中的自定义信息窗口后如何取消选择 GMSMarker【英文标题】:How to deselect a GMSMarker after removing custom infowindow in google maps swift 【发布时间】:2021-03-15 07:55:11 【问题描述】:

所以我一直在使用 Google Maps ios SDK 4.0.0,当我点击标记时我的要求是这样的,它应该添加 UIViewContoller 的视图,我很容易实现。看看下面的代码:

var customeVC:CustomViewController?

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool 
    
    customeVC = CustomViewController(nibName: "CustomViewController", bundle: nil)
    customeVC?.delegate = self
    self.addChild(customeVC!)
    customeVC?.view.frame = self.view.frame
    self.view.addSubview(customeVC!.view)
    customeVC?.didMove(toParent: self)

    // Remember to return false
    // so marker event is still handled by delegate
    return false



func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? 
    
    //Empty the default infowindow
    return UIView()



extension MapViewController: CustomViewControllerDelegate 
    // Triggers when I close the full screen view of CustomViewController
    func didCloseWindow() 
        customeVC?.willMove(toParent: nil)
        customeVC?.removeFromParent()
        customeVC?.view.removeFromSuperview()
        customeVC = nil
    

现在主要的问题是,在关闭窗口/视图后,如果我再次(第二次)单击相同的标记,它不会显示视图。但如果我再次点击(第三次),它就会显示出来。

所以我怀疑在删除视图后标记不会被取消选择。但是当我第二次点击时,它会被取消选择,第三次点击会再次被选中。

我在 CustomViewController 中有文本字段和按钮,这就是为什么我没有在委托函数 mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? 中添加这个视图。基本上我遵循了这个article,它可以让你点击InfoWindow。

在删除视图时,我还尝试在 didTap 委托方法和 mapView.selectedMarker = nil 中使用 mapView.selectedMarker = marker

如何取消选择标记,以便每次单击同一个标记时都应显示视图?

任何帮助将不胜感激。提前致谢。

【问题讨论】:

【参考方案1】:

试了几天终于解决了。基本上,只有当您只绘制标记时,每次点击标记才有效。但是,如果您在叠加层或多边形内绘制标记,则第二次点击相同的标记不起作用,因为第二次触发了以下 GMSMapViewDelegate 方法。

func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay)

我没有提到,我在叠加层内绘制标记,因为我从没想过它会导致点击问题。我发现其他人早些时候也遇到过issue,但他的问题没有得到回答。因此,这是我需要在该委托方法中进行更新以使其工作的内容,其余代码相同。

当我点击某个多边形时,我将isTappable 多边形属性设置为false,然后我可以玩弄内部绘制的标记。 此外,只要用户单击其他多边形,我就会将 isTappable 属性重置为先前选择的多边形的 true

class ViewController: GMSMapViewDelegate 
    @IBOutlet weak var mapView:GMSMapView!
    private var selectedPolygon: GMSAptivePolygon?
    
    func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) 
        
        if let polygon = overlay as? GMSPolygon 
            
            // Make sure to restrict markers for a polygon if tapped more than once
            if selectedPolygon != polygon 
                
                // Reset polygon to tappable
                selectedPolygon?.isTappable = true
                
                // Fetch all annotations of this polygon if exits
                fetchMarkers(for: polygon)
                
                polygon.isTappable = false
                selectedPolygon = polygon
            
        
    

【讨论】:

【参考方案2】:

我怀疑您的问题更多地与您如何呈现和解除您的 CustomViewController 有关,因为无论状态如何,都应该调用 didTap 委托方法。

最初我会添加一个测试来检查是否每次点击标记实际上都会触发委托方法,并将您的一些演示代码移动到此委托方法之外的更简洁的方法中,例如

func showCustomView() 
    // make sure any previous CustomViewController are removed
    if let vc = self.customeVC 
        vc.willMove(toParent: nil)
        vc.removeFromParent()
        vc.view.removeFromSuperview()
        self.customeVC = nil
    
    // initialise a new CustomViewController
    let cv = CustomViewController(
        nibName: "CustomViewController", 
        bundle: nil
    )
    cv.delegate = self
    self.addChild(cv)
    cv.view.frame = self.view.frame
    self.view.addSubview(cv.view)
    cv.didMove(toParent: self)
    self.customeVC = cv


func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool 
    // print to check the marker is being tapped
    print("marker was tapped")
    // run presentation code
    showCustomView()
    // return true to prevent the map from
    // performing its default selection behaviour
    return true


我没有对此进行测试,但我希望它可以帮助您解决问题,让我知道您的进展情况。


我会考虑的另一件事是以模态方式呈现CustomViewController,而不是使用modalPresentationStyle 在其他视图之上显示自定义视图,而无需像现在一样将其添加为子视图。

你的CustomerViewControllers init 中需要这样的东西

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) 
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    self.modalPresentationStyle = .overCurrentContext
    self.modalTransitionStyle = .crossDissolve
    self.modalPresentationCapturesStatusBarAppearance = true

然后您将showCustomView() 方法更改为类似的内容

func showCustomView() 
    // make sure any previous CustomViewController are removed
    if let vc = self.customeVC 
        vc.dismiss(animated: true)
        self.customeVC = nil
    
    // initialise a new CustomViewController
    let cv = CustomViewController(
        nibName: "CustomViewController", 
        bundle: nil
    )
    cv.delegate = self
    self.present(cv, animated: true, completion: nil)
    self.customeVC = cv

这也假设您必须先关闭CustomViewController,然后才能与地图的任何其他部分进行交互,您在此处尝试实现的屏幕截图可能会帮助其他人帮助您。

【讨论】:

感谢您的帮助。我尝试使用相同的代码 addSubviewmodalPresentationStyle 但关闭 CustomViewController 后点击同一标记时 didTap 不会被触发。 我刚刚用我的代码库进行了测试,每次点击标记(选中和未选中)时都会调用 didTap 方法 - 自定义视图是否可能会留下你点击的不可见的东西? - 我会注释掉您添加CustomViewController 的位置,然后尝试仅使用print("tapped") 进行测试。 我这样做了,但是当我点击同一个标记时didTap 方法没有触发,但是如果我点击其他标记,它就会被调用。除了didTap,我没有任何其他委托方法,就像你的一样。这是该问题的一瞥media.giphy.com/media/MzMZ1rZZFPU49d3wpV/giphy.gif 您是否在您的markerInfoWindow 委托方法中尝试过return nil?您添加的空信息窗口可能导致问题? 您需要进行更多调试,首先注释掉并初始化自定义叠加层,然后慢慢删除内容,直到您每次都可以点击标记。然后慢慢地重新引入东西,直到找到它中断的点,然后从那里调试。在关闭自定义叠加层后,我还会使用Xcode's debug view hierarchy button 来检查用户界面。

以上是关于删除谷歌地图中的自定义信息窗口后如何取消选择 GMSMarker的主要内容,如果未能解决你的问题,请参考以下文章

如何从弹出的谷歌地图信息窗口中删除关闭按钮(x)边框?

当你从谷歌地图API中点击地图中的内置位置(不是标记)时,如何自定义弹窗的内容?

为 Android 显示自定义信息窗口 Android 地图实用程序库

带有两个可点击按钮或 ImageView 的 Google 地图 v2 自定义信息窗口

如何在 Android 中以编程方式触发自定义信息窗口

如何修复谷歌地图中的信息窗口