如何在UIView中绘制与MKPolyline相同的UIBezierPath?

5

目前我正在使用MKMapView跟踪我的位置。我的目标是绘制一个与从跟踪位置创建的MKPolyline相同的贝塞尔路径。

我尝试的方法是:将所有位置坐标存储在CLLocation数组中。迭代该数组并将纬度/经度坐标存储在CLLocationCoordinate2D数组中。然后确保折线在屏幕视图中,然后将所有位置坐标转换为CGPoints。

当前尝试:

@IBOutlet weak var bezierPathView: UIView! 

var locations = [CLLocation]() // values from didUpdateLocation(_:)

func createBezierPath() {
    bezierPathView.isHidden = false

        var coordinates = [CLLocationCoordinate2D]()
        for location in locations {
            coordinates.append(location.coordinate)
        }

        let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
        fitPolylineInView(polyline: polyline)

        let mapPoints = polyline.points()

        var points = [CGPoint]()

        for point in 0...polyline.pointCount
        {
            let coordinate = MKCoordinateForMapPoint(mapPoints[point])
            points.append(mapView.convert(coordinate, toPointTo: polylineView))
        }

        print(points)

        let path = UIBezierPath(points: points)
        path.lineWidth = 2.0
        path.lineJoinStyle = .round

        let layer = CAShapeLayer(path: path, lineColor: UIColor.red, fillColor: UIColor.black)
        bezierPathView.layer.addSublayer(layer)
}

extension UIBezierPath {
    convenience init(points:[CGPoint])
    {
        self.init()

        //connect every points by line.
        //the first point is start point
        for (index,aPoint) in points.enumerated()
        {
            if index == 0 {
                self.move(to: aPoint)
            }
            else {
                self.addLine(to: aPoint)
            }
        }
    }
}

extension CAShapeLayer
{
    convenience init(path:UIBezierPath, lineColor:UIColor, fillColor:UIColor)
    {
        self.init()
        self.path = path.cgPath
        self.strokeColor = lineColor.cgColor
        self.fillColor = fillColor.cgColor
        self.lineWidth = path.lineWidth

        self.opacity = 1
        self.frame = path.bounds
    }
}

我能将从convert(_:)方法中存储的点输出到控制台(不确定它们是否正确)。但是,bezierPathView上没有输出结果,导致视图控制器显示为空白背景。

@MirekE 调整好了!我现在正在从CLLocationManagerDelegate方法didUpdateLocations中获取坐标。我已经成功地创建了一个MKPolyline,只是不知道如何创建与折线完全相同的UIBezierPath,以便将其放置在UIView或某个对象中表示所采取的路径。 - lifewithelliott
尝试打印点以检查值。它们看起来正确吗?UIBezierPath(points :)初始化程序在做什么?我在文档中没有看到它... - MirekE
你在谈论折线,但我在你的代码中没有看到它。如果你正在创建和绘制实际的MKPolyline,我想知道为什么你需要贝塞尔曲线。 - MirekE
@MirekE 我感觉我已经接近解决方案了,我已经更新了代码到最新的发现,但仍然无法绘制路径。有什么可能的建议吗?谢谢! - lifewithelliott
@MirekE 无论我尝试了什么来使得点在范围内,都没有绘制出BezierPath。 - lifewithelliott
显示剩余6条评论
2个回答

1
您的扩展功能很好。问题可能在于将图层添加到视图的代码(您没有展示此部分代码)。
我建议您简化项目,例如使用预定义的点数组,这些点肯定适合您的视图。例如,对于宽度为500像素,高度为300像素的视图,您可以使用类似以下内容的东西:
let points = [
    CGPoint(x: 10, y: 10),
    CGPoint(x: 490, y: 10),
    CGPoint(x: 490, y: 290),
    CGPoint(x: 10, y: 290),
    CGPoint(x: 10, y: 10)
]

使用颜色要明显可见,例如黑色和黄色作为描边和填充。

确保你的路径正确添加到视图中,例如:

let path = UIBezierPath(points: points)

let shapeLayer = CAShapeLayer(path: path, lineColor: UIColor.blue, fillColor: UIColor.lightGray)

view.layer.addSublayer(shapeLayer)

在Xcode的Interface Builder中检查包含视图的控制器。在调试视图层次结构函数中:

enter image description here


我不确定我能改变什么,但肯定取得了进展。为了更好的呈现,我将UIView的背景设置为透明。现在正在尝试弄清楚如何确保整个折线在视图的范围内绘制。是否可能调整BezierPath的大小,并将其居中/缩放以适合任何给定的视图?我认为我能够重新定位折线的点在视图内部。但是像你之前说的那样,2000多个 x 点肯定超出了屏幕!抱歉让你陷入我的兔子洞里! - lifewithelliott
请参考以下链接:https://developer.apple.com/reference/uikit/uibezierpath/1624340-apply。如果点a超出了专利范围,请在Xcode的Interface Builder中检查包含视图的控制器,使用“debug view hierarchy”功能。 - MirekE

0

如果你还没有解决这个问题,这可能会对你有所帮助。

我想要将MKPolyline的形状作为一张没有背景的图片。我使用了上面的代码作为灵感,并且遇到了和你一样的问题,路线没有显示出来。

实际上,我认为这是一种缩放问题。至少在游乐场里看起来是这样的。无论如何,通过这些方法,我得到了一张折线形状的图片。

private func createPolylineShapeAsImage() -> UIImage? {
    let vw = UIView(frame: mapView.bounds)
    var image : UIImage?
    if let polyline = viewModel.tourPolyline {
        let path = createBezierPath(mapView, polyline, to: mapView)
        let layer = getShapeLayer(path: path, lineColor: UIColor.white, fillColor: .clear)
        vw.layer.addSublayer(layer)
        image = vw.asImage()
    }
    return image
}

func createBezierPath(_ mapView : MKMapView, _ polyline : MKPolyline, to view : UIView) -> UIBezierPath  {
    let mapPoints = polyline.points()
    var points = [CGPoint]()
    let max = polyline.pointCount - 1
    for point in 0...max {
       let coordinate = mapPoints[point].coordinate
       points.append(mapView.convert(coordinate, toPointTo: view))
    }
    let path = UIBezierPath(points: points)
    path.lineWidth = 5.0
    return path
}

private func getShapeLayer(path:UIBezierPath, lineColor:UIColor, fillColor:UIColor) -> CAShapeLayer {
    let layer = CAShapeLayer()
    layer.path = path.cgPath
    layer.strokeColor = lineColor.cgColor
    layer.fillColor = fillColor.cgColor
    layer.lineWidth = path.lineWidth

    layer.opacity = 1
    layer.frame = path.bounds
    return layer
}

要获取视图的图像,请使用此扩展。

import UIKit
extension UIView {
  // Using a function since `var image` might conflict with an existing variable
  // (like on `UIImageView`)
  func asImage() -> UIImage {
    if #available(iOS 10.0, *) {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    } else {
        UIGraphicsBeginImageContext(self.frame.size)
        self.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return UIImage(cgImage: image!.cgImage!)
    }
  }
}

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