How to detect taps on MKPolylines/Overlays like Maps.app?

后端 未结 8 892
梦谈多话
梦谈多话 2020-12-23 02:09

When displaying directions on the built-in Maps.app on the iPhone you can \"select\" one of the usually 3 route alternatives that are displayed by tapping on it. I wan\'t to

8条回答
  •  悲&欢浪女
    2020-12-23 02:45

    @Rashwan L : Updated his answer to Swift 4.2

    let map = MKMapView()
    let mapTap = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
     map.addGestureRecognizer(mapTap)
    
     @objc private func mapTapped(_ tap: UITapGestureRecognizer) {
        if tap.state == .recognized && tap.state == .recognized {
            // Get map coordinate from touch point
            let touchPt: CGPoint = tap.location(in: skyMap)
            let coord: CLLocationCoordinate2D = skyMap.convert(touchPt, toCoordinateFrom: skyMap)
            let maxMeters: Double = meters(fromPixel: 22, at: touchPt)
            var nearestDistance: Float = MAXFLOAT
            var nearestPoly: MKPolyline? = nil
            // for every overlay ...
            for overlay: MKOverlay in skyMap.overlays {
                // .. if MKPolyline ...
                if (overlay is MKPolyline) {
                    // ... get the distance ...
                    let distance: Float = Float(distanceOf(pt: MKMapPoint(coord), toPoly: overlay as! MKPolyline))
                    // ... and find the nearest one
                    if distance < nearestDistance {
                        nearestDistance = distance
                        nearestPoly = overlay as? MKPolyline
                    }
    
                }
            }
    
            if Double(nearestDistance) <= maxMeters {
                print("Touched poly: \(nearestPoly) distance: \(nearestDistance)")
    
            }
        }
    }
    
    private func distanceOf(pt: MKMapPoint, toPoly poly: MKPolyline) -> Double {
        var distance: Double = Double(MAXFLOAT)
        for n in 0.. 1.0 {
                ptClosest = ptB
            }
            else {
                ptClosest = MKMapPoint(x: ptA.x + u * xDelta, y: ptA.y + u * yDelta)
            }
    
            distance = min(distance, ptClosest.distance(to: pt))
        }
        return distance
    }
    
    private func meters(fromPixel px: Int, at pt: CGPoint) -> Double {
        let ptB = CGPoint(x: pt.x + CGFloat(px), y: pt.y)
        let coordA: CLLocationCoordinate2D = skyMap.convert(pt, toCoordinateFrom: skyMap)
        let coordB: CLLocationCoordinate2D = skyMap.convert(ptB, toCoordinateFrom: skyMap)
        return MKMapPoint(coordA).distance(to: MKMapPoint(coordB))
    }
    

提交回复
热议问题