iOS Mapbox 拖动标注时更新地图会将标注恢复到原始坐标

4

我正在尝试在拖动注释时更新一些地图组件,例如突出显示特定的MGLPolygon并在注释已拖动到边缘时平移地图。 我将使用后者来解决这个问题。

我尝试了https://docs.mapbox.com/ios/maps/examples/draggable-views/上的代码,并添加了一些行。 这是带有我的更改的精确复制品。

import Mapbox

// Example view controller
class ViewController: UIViewController, MGLMapViewDelegate {

  var mapView: MGLMapView!

  override func viewDidLoad() {
    super.viewDidLoad()

    mapView = MGLMapView(frame: view.bounds)
    mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    mapView.styleURL = MGLStyle.streetsStyleURL
    mapView.tintColor = .darkGray
    mapView.zoomLevel = 1
    mapView.delegate = self
    view.addSubview(mapView)

    // Specify coordinates for our annotations.
    let coordinates = [
      CLLocationCoordinate2D(latitude: 0, longitude: -70),
      CLLocationCoordinate2D(latitude: 0, longitude: -35),
      CLLocationCoordinate2D(latitude: 0, longitude: 0),
      CLLocationCoordinate2D(latitude: 0, longitude: 35),
      CLLocationCoordinate2D(latitude: 0, longitude: 70)
    ]

    // Fill an array with point annotations and add it to the map.
    var pointAnnotations = [MGLPointAnnotation]()
    for coordinate in coordinates {
      let point = MGLPointAnnotation()
      point.coordinate = coordinate
      point.title = "To drag this annotation, first tap and hold."
      pointAnnotations.append(point)
    }

    mapView.addAnnotations(pointAnnotations)
  }

  // MARK: - MGLMapViewDelegate methods

  // This delegate method is where you tell the map to load a view for a specific annotation. To load a static MGLAnnotationImage, you would use `-mapView:imageForAnnotation:`.
  func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
    // This example is only concerned with point annotations.
    guard annotation is MGLPointAnnotation else {
      return nil
    }

    // For better performance, always try to reuse existing annotations. To use multiple different annotation views, change the reuse identifier for each.
    if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "draggablePoint") {
      return annotationView
    } else {
      let dav = DraggableAnnotationView(reuseIdentifier: "draggablePoint", size: 50)
      dav.mapView = mapView
      return dav
    }
  }

  func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
    return true
  }
}

// MGLAnnotationView subclass
class DraggableAnnotationView: MGLAnnotationView {
  var mapView: MGLMapView!
  var screen: CGRect!
  var mapBounds: CGRect!

  init(reuseIdentifier: String, size: CGFloat) {
    super.init(reuseIdentifier: reuseIdentifier)

    // `isDraggable` is a property of MGLAnnotationView, disabled by default.
    isDraggable = true

    // This property prevents the annotation from changing size when the map is tilted.
    scalesWithViewingDistance = false

    // Begin setting up the view.
    frame = CGRect(x: 0, y: 0, width: size, height: size)

    backgroundColor = .darkGray

    // Use CALayer’s corner radius to turn this view into a circle.
    layer.cornerRadius = size / 2
    layer.borderWidth = 1
    layer.borderColor = UIColor.white.cgColor
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOpacity = 0.1

    screen = UIScreen.main.bounds
    mapBounds = CGRect(
      x: screen.origin.x + 20,
      y: screen.origin.y + 20,
      width: screen.size.width - 40,
      height: screen.size.height - 40)
  }

  // These two initializers are forced upon us by Swift.
  override init(frame: CGRect) {
    super.init(frame: frame)
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // Custom handler for changes in the annotation’s drag state.
  override func setDragState(_ dragState: MGLAnnotationViewDragState, animated: Bool) {
    super.setDragState(dragState, animated: animated)

    switch dragState {
    case .starting:
      print("Starting", terminator: "")
      startDragging()
    case .dragging:
      let pointCoordinate = self.mapView.convert(center, toCoordinateFrom: nil)

      if mapBounds.contains(center) {
        DispatchQueue.main.async {
          self.mapView.setCenter(pointCoordinate, animated: true)
        }
      }

      print(".", terminator: "")
    case .ending, .canceling:
      print("Ending")
      endDragging()
    case .none:
      break
    @unknown default:
      fatalError("Unknown drag state")
    }
  }

  // When the user interacts with an annotation, animate opacity and scale changes.
  func startDragging() {
    UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
      self.layer.opacity = 0.8
      self.transform = CGAffineTransform.identity.scaledBy(x: 1.5, y: 1.5)
    }, completion: nil)

    // Initialize haptic feedback generator and give the user a light thud.
    if #available(iOS 10.0, *) {
      let hapticFeedback = UIImpactFeedbackGenerator(style: .light)
      hapticFeedback.impactOccurred()
    }
  }

  func endDragging() {
    transform = CGAffineTransform.identity.scaledBy(x: 1.5, y: 1.5)
    UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
      self.layer.opacity = 1
      self.transform = CGAffineTransform.identity.scaledBy(x: 1, y: 1)
    }, completion: nil)

    // Give the user more haptic feedback when they drop the annotation.
    if #available(iOS 10.0, *) {
      let hapticFeedback = UIImpactFeedbackGenerator(style: .light)
      hapticFeedback.impactOccurred()
    }
  }
}


每次调用 self.mapView.setCenter(pointCoordinate, animated: true) 时,注释会来回移动到其原始位置。

1
我也遇到了完全相同的问题。有解决方法吗?在我的情况下,我正在构建一个“测量工具”,它是两个可拖动点注释。我有一个MGLPolyline特征,连接这两个点。当我同时拖动一个点并移动线时,该点注释会在原始位置和手指位置之间快速翻转。 - jaredrada
1
我所做的是将自己的UIPanGestureRecognizer添加到我的DraggableAnnotationView上。在我的UIPanGestureRecognizer回调中,我使用转换为CLLocationCoordinate2D的手势CGPoint更新DraggableAnnotationView的坐标。 - Adonis Dumadapat
1
@AdonisDumadapat 非常感谢您的建议,现在完美无缺。 - Sarthak Mishra
2
嘿,@jaredrada,是的,在viewFor方法中,在创建annotationView时传递注释对象。在构建视图时,使用注释的坐标属性来更新其位置。请删除第二个评论,以避免向用户发送垃圾邮件。 - Sarthak Mishra
1
已添加答案 @zephyr - Sarthak Mishra
显示剩余6条评论
1个回答

1

以下是解释Adonis方案的代码。基本上,将平移手势添加到自定义注释视图中,并在注释平移时更新坐标。

class CustomDraggableAnnotaionView: MGLAnnotationView {


required init(
    reuseIdentifier: String?,
    image: UIImage?,
    annotation: CustomMapGLAnnotaion
) {
    super.init(reuseIdentifier: reuseIdentifier)

    setupDraggableAnnotations()
    self.layer.zPosition = 10
}

required init?(coder _: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

// MARK: - Draggable annotation handlers

private func setupDraggableAnnotations() {
    addDraggableAnnotationGestureRecognizers()
}

private func addDraggableAnnotationGestureRecognizers() {
    let panGesture = UIPanGestureRecognizer(
        target: self,
        action: #selector(self.draggedView(_:))
    )
    let tapGesture = UITapGestureRecognizer(
        target: self,
        action: #selector(self.tappedAnnotation(_:))
    )
    self.isUserInteractionEnabled = true
    self.addGestureRecognizer(panGesture)
    self.addGestureRecognizer(tapGesture)
    for recognizer in self.gestureRecognizers! where recognizer is UITapGestureRecognizer {
        tapGesture.require(toFail: recognizer)
    }
    for recognizer in self.gestureRecognizers! where recognizer is UIPanGestureRecognizer {
        panGesture.require(toFail: recognizer)
    }
}

@objc func draggedView(_ sender: UIPanGestureRecognizer) {
    annotationObject?.draggable!.isCurrentlyDragging = true
    let point = sender.location(in: MapManager.shared.mapView)
    let coordinates = MapManager.shared.mapView.convert(
        point,
        toCoordinateFrom: MapManager.shared.mapView
    )

    annotationObject?.coordinate = coordinates

    if sender.state == .ended {
        // endDragging()
    } else if sender.state == .began {
        // startDragging()
        annotationObject?.draggable!.handler.didStartDragging()
    } else {
        // 
    }
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接