自定义 MapView 类 Swift

问题描述

我遇到了一些重大问题,需要一些帮助。我正在使用 What3Words 公司的一些代码。他们创建了一个自定义类:

open class MapView: MKMapView,MKMapViewDelegate,UIGestureRecognizerDelegate,CLLocationManagerDelegate {
//all their code is here
}

我的目标是使用点击手势从地图中获取纬度/经度。使用 MapViewKit 插入时,我可以非常轻松地完成此操作,并使对象符合 MKMapView!


    @IBOutlet weak var map: MKMapView!
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    @IBAction func tapped(_ sender: UITapGestureRecognizer) {
        print("hey")
    let tap = sender
        let coord = tap.location(in: map)
        print(coord)
        print(tap.location(in: self))
        print(tap.location(in: map))
        map.convert(coord,to: map)
        print(map.convert(coord,to: map))
        
    }

}

但是,如果我符合它 MKMapView!我无法访问公开课中的任何专业代码。 如果我符合公开课,我不知道如何使用我的点击手势。

我应该在我希望地图出现的任何 VC 中调用下面的代码

    super.viewDidLoad()

    let map = MapViewController(frame: view.frame)
    map.set(api: api)
    map.set(center: "school.truck.lunch",latitudeSpan: 0.05,longitudeSpan: 0.05)
    map.showsUserLocation = true

    
    map.onError = { error in
      self.showError(error: error)
    }
    
    self.view = map
}

  // MARK: Show an Error
  
  /// display an error using a UIAlertController,error messages conform to customstringconvertible
  func showError(error: Error) {
    dispatchQueue.main.async {
      let alert = UIAlertController(title: "Error",message: String(describing: error),preferredStyle: .alert)
      alert.addAction(UIAlertAction(title: "dismiss",style: .cancel,handler: nil))
      self.present(alert,animated: true)
    }
  }

知道如何在仍然使用这个特殊课程的同时让点击手势起作用吗?我觉得我什么都试过了。啊!!请协助。

解决方法

最简单的方法是将以下内容添加到您的 ViewController 中:

override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) {
    if let location = touches.first?.location(in: map) {
      map.screenCoordsToWords(point: location) { square in
        print(square.words ?? "")
      }
    }
  }

并在您的 MapView 类中添加:

func screenCoordsToWords(point: CGPoint,completion: @escaping (W3WSquare) -> () ) {
  let coordinates = convert(point,toCoordinateFrom: self)
  self.api?.convertTo3wa(coordinates: coordinates,language: "en") { square,error in
    if let s = square {
      completion(s)
    }
  }
}

但是这样做会导致 MKMapView 的触摸事件处理程序和您的视图控制器之间产生混淆。这可能是好的,也可能是不好的。

如果这是一个问题,您可以改为在 MapView 中附加一个手势识别器,但有一个技巧可以防止覆盖 MKMapView 的内置双击识别器:

  func addGesture() {
    /// when the user taps the map this is called and it gets the square info
    let tap = UITapGestureRecognizer(target: self,action: #selector(tapped))
    tap.numberOfTapsRequired = 1
    tap.numberOfTouchesRequired = 1
    
    // A kind of tricky thing to make sure double tap doesn't trigger single tap in MKMapView
    let doubleTap = UITapGestureRecognizer(target: self,action:nil)
    doubleTap.numberOfTapsRequired = 2
    addGestureRecognizer(doubleTap)
    tap.require(toFail: doubleTap)
    
    tap.delegate = self
    
    addGestureRecognizer(tap)
  }

  
  @objc func tapped(_ gestureRecognizer : UITapGestureRecognizer) {
    let location = gestureRecognizer.location(in: self)
    let coordinates = convert(location,toCoordinateFrom: self)
    api?.convertTo3wa(coordinates: coordinates,error in
      if let s = square {
        print(s.words ?? "")
      }
    }
  }

然后在您的 ViewController 的 viewDidLoad 中进行设置:

map.addGesture()