【问题标题】:Why MKPolyline lagged when user drawing?为什么 MKPolyline 在用户绘图时滞后?
【发布时间】:2019-08-01 16:14:20
【问题描述】:

当用户在屏幕上移动手指时,我想绘制一条折线。我根据一些文章编写代码,它可以工作到一定程度。在某些时候,一切都开始滞后,应用程序崩溃。

我尝试清理叠加层并减少点数,但没有帮助。

  var rendersWorkaround: [MKOverlayRenderer] = []
  var currentRender: MKOverlayRenderer?

  var points: [CLLocationCoordinate2D] = []

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.rendersWorkaround.forEach { item in
      self.mapView.removeOverlay(item.overlay)
    }
    self.rendersWorkaround = []
    self.points = []
    if let touch = touches.first {
      let coordinate = mapView.convert(touch.location(in: mapView), toCoordinateFrom: mapView)
      points.append(coordinate)
    }
  }

  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

//    if self.lastTouchTime != nil && (Date().timeIntervalSinceReferenceDate - self.lastTouchTime!) < 0.025 { return }
    if self.rendersWorkaround.count > 10 {
      let countForDelete: Int = Int((Double(self.rendersWorkaround.count) / 2.0).rounded())
      for index in 0...countForDelete {
        self.mapView.removeOverlay(self.rendersWorkaround[index].overlay)
      }
      self.rendersWorkaround.removeSubrange(0...countForDelete)
    }
    if let touch = touches.first {
      let coordinate = mapView.convert(touch.location(in: mapView), toCoordinateFrom: mapView)
      points.append(coordinate)
      if points.count > 299 {
        points = points.indices.compactMap { return $0 % 2 != 0 ? points[$0] : nil }
      }
      let polyline = MKPolyline(coordinates: points, count: points.count)
      mapView.addOverlay(polyline)
    }
  }

  override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    let polygon = MKPolygon(coordinates: &points, count: points.count)
    mapView.addOverlay(polygon)
    points = []
  }

  func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKPolyline {
      let polylineRenderer = MKPolylineRenderer(overlay: overlay)
      polylineRenderer.strokeColor = .orange
      polylineRenderer.lineWidth = 5
      self.rendersWorkaround.append(polylineRenderer)
      self.currentRender = polylineRenderer
      return polylineRenderer
    } else if overlay is MKPolygon {
      let polygonView = MKPolygonRenderer(overlay: overlay)
      polygonView.fillColor = .magenta
      self.rendersWorkaround.append(polygonView)
      return polygonView
    }

    return  MKTileOverlayRenderer(overlay: overlay)
  }

【问题讨论】:

    标签: swift mapkit mkmapview mkpolyline


    【解决方案1】:

    是的,我在 iOS 13 更新后注意到了这一点。 Apple 做了很多地图更新,现在“rendererFor 覆盖”已经滞后。我不知道为什么。我最终移动到覆盖地图的 UIView。用户可以在该视图上绘制然后我将接触点转换为 mapView。所以最后会调用 rendererFor。

    此页面上有一个答案,他们正在做类似的事情。 iOS + MKMapView user touch based drawing

    这是我的代码:

    import Foundation
    
    struct DrawViewViewModel {
        let lineColor: UIColor
        let lineWidth: CGFloat
    }
    
    protocol DrawViewDelegate: AnyObject {
        func touchesEnded(points: [CGPoint])
    }
    
    class DrawView: UIView {
        weak var delegate: DrawViewDelegate?
        private var lineArray: [CGPoint] = [CGPoint]()
        var firstPoint = CGPoint.zero
        
        var viewModel: DrawViewViewModel?
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            
            // 2
            guard let touch = touches.first else { return }
            firstPoint = touch.location(in: self)
            
            // 3
            lineArray.append(firstPoint)
        }
        
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            guard let touch = touches.first else { return }
            let currentPoint = touch.location(in: self)
            lineArray.append(currentPoint)
            setNeedsDisplay()
        }
        
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            guard let touch = touches.first else { return }
            let currentPoint = touch.location(in: self)
            lineArray.append(currentPoint)
            delegate?.touchesEnded(points: lineArray)
            
            //delete draw lines
            lineArray = []
            setNeedsDisplay()
        }
        
        override func draw(_ rect: CGRect) {
            guard let context = UIGraphicsGetCurrentContext() else { return }
            draw(inContext: context)
        }
        
        func draw(inContext context: CGContext) {
            
            // 2
            if let VM = viewModel {
                context.setLineWidth(VM.lineWidth)
                context.setStrokeColor(VM.lineColor.cgColor)
            }
            context.setLineCap(.round)
            
            // 3
            for (index, point) in lineArray.enumerated() {
                
                // 4
                context.beginPath()
                context.move(to: point)
                if index+1 < lineArray.count {
                    context.addLine(to: lineArray[index+1])
                }
                
                context.strokePath()
            }
        }
    }
    
    
    

    接下来是我的 MKMapView 正在使用的委托:

    //MARK - DrawViewDelegate
        func touchesEnded(points: [CGPoint]) {
            let mapPoints = convertPointsToCords(points: points)
            let polygon = MKPolygon(coordinates: mapPoints, count: mapPoints.count)
            
            let worldPoly = getWorldPoly()
            let polygonInverted = MKPolygon(coordinates: worldPoly, count: worldPoly.count, interiorPolygons: [polygon]) //create an inverted polygon
            
            coreMapView.addOverlay(polygonInverted) //Add polygon areas
            
            //Then run the search
            // update search criteria
            updateSearchCriteria(polygonBoundPoints: mapPoints)
            
            // move map
            coreMapView.zoomToPolygon(polygon: polygon)// make sure to call this after we hang the DnDSign
            
            // allow map movement and disable drawing
            coreMapView.isScrollEnabled = true
            coreMapView.isZoomEnabled = true
            coreMapView.isUserInteractionEnabled = true
        }
    
    func convertPointsToCords(points:[CGPoint]) -> [CLLocationCoordinate2D] {
            var mapPoints = [CLLocationCoordinate2D]()
            for point in points {
                let convertedPoint = mapDrawView.convert(point, to: coreMapView)
                let coordinate = coreMapView.convert(convertedPoint, toCoordinateFrom: coreMapView)
                mapPoints.append(coordinate)
    
            }
            return mapPoints
        }
    

    如果你想要像我这里的倒置多边形是世界多边形,所以你可以把你的放在里面。

    func getWorldPoly() -> [CLLocationCoordinate2D] {
            return [CLLocationCoordinate2D(latitude: 90, longitude: 0),
                    CLLocationCoordinate2D(latitude: 90, longitude: 180),
                    CLLocationCoordinate2D(latitude: -90, longitude: 180),
                    CLLocationCoordinate2D(latitude: -90, longitude: 0),
                    CLLocationCoordinate2D(latitude: -90, longitude: -180),
                    CLLocationCoordinate2D(latitude: 90, longitude: 180)]
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-03
      • 2020-11-15
      • 2017-09-29
      相关资源
      最近更新 更多