【问题标题】:Can't get Swift UIBezierPath plot to remove and then update无法让 Swift UIBezierPath 绘图删除然后更新
【发布时间】:2021-10-29 01:07:33
【问题描述】:

在我的应用程序中,viewdidLoad() 使用 UIBezierPath 显示绿色 UIBezierPath 绘制线。
但稍后在程序中,事件回调使用相同的 UIBezierPath 删除所有点并在绿色旁边显示红线。
但是,它所做的只是在同一位置将绿线变为红色。

最终,我想使用 UIBezierPath 来显示一个不断变化的多线图—— 即:每秒删除以前的多线图并显示更新的多线图。

显示绿线的代码......................

    var sensor_plot_UIBezierPath = UIBezierPath()
var sensor_plot_CAShapeLayer = CAShapeLayer()

override func viewDidLoad() 
{
                sensor_plot_UIBezierPath.move(to: CGPoint(  x: 100, 
                                                            y: 100))
                sensor_plot_UIBezierPath.addLine( to: CGPoint(  x:  200,
                                                                y:  200 ) )
        init_app_display()

        ...start background events...
}

func init_app_display()
{
    sensor_plot_CAShapeLayer.path = sensor_plot_UIBezierPath.cgPath
    sensor_plot_CAShapeLayer.fillColor = UIColor.clear.cgColor       // doesn't matter
    sensor_plot_CAShapeLayer.strokeColor = UIColor.green.cgColor
    sensor_plot_CAShapeLayer.lineWidth = 3.0

    view.layer.addSublayer( sensor_plot_CAShapeLayer )
}

应该在它旁边显示红线的代码..................
(但实际上将初始绿线变为红色,在同一位置 - 第一行旁边没有第二行)

...display_plot_update() is called by event from background thread (specifically, BLE event didUpdateValueFor)

    func display_plot_update()
    {
        DispatchQueue.main.async
        {
            self.sensor_plot_UIBezierPath.removeAllPoints()
            self.sensor_plot_UIBezierPath.move(to: CGPoint(     x: 110, 
                                                                y: 100))
            self.sensor_plot_UIBezierPath.addLine( to: CGPoint(  x:  210,
                                                                 y:  200 ) )
            self.sensor_plot_CAShapeLayer.strokeColor = UIColor.red.cgColor
        }
    }

【问题讨论】:

  • 你为什么在视图控制器下玩UIBezierPathCAShapeLayer?一个叫“init_app_display”的人是从哪里来的?

标签: ios swift uibezierpath


【解决方案1】:

您不会显示在形状层中安装路径的代码,或将形状层安装为视图控制器视图的子层的代码。您应该显示该代码,以便我们可以看到您在做什么。您还应该显示init_app_display() 函数的代码。

我假设你在某处有这样的代码:

sensor_plot_CAShapeLayer.path = self.sensor_plot_UIBezierPath.cgPath

和类似的代码

view.layer.addSublayer(sensor_plot_CAShapeLayer)

您似乎认为将 CAShapeLayer 的路径设置为特定的贝塞尔路径会将形状层链接到该路径,并且更新路径会更新形状层。它不是那样工作的。更改路径后,您需要将新路径安装到形状图层中。

您可以像这样更改display_plot_update() 函数:

func display_plot_update()
{
    DispatchQueue.main.async
    {
        // Create a new bezier path.
        let newPath = UIBezierPath()
        newPath.move(to: CGPoint(     x: 110, 
                                      y: 100))
        newPath.addLine( to: CGPoint( x: 210,
                                      y: 200 ) )
        self.sensor_plot_CAShapeLayer.strokeColor = UIColor.red.cgColor
        self.sensor_plot_CAShapeLayer.path = newPath.cgPath // The important part
    }
}

这会将线移动到您的新坐标并使其变为红色。

如果您想在第一行旁边添加第二行,请编写 `display_plot_update()~ 函数,如下所示:

func display_plot_update()
{
    DispatchQueue.main.async
    {
        // Add the new line to the existing path (without clearing it)
        self.sensor_plot_UIBezierPath.move(to: CGPoint(     x: 110, 
                                      y: 100))
        self.sensor_plot_UIBezierPath.addLine( to: CGPoint( x: 210,
                                      y: 200 ) )
        self.sensor_plot_CAShapeLayer.strokeColor = UIColor.red.cgColor
        sensor_plot_CAShapeLayer.path = self.sensor_plot_UIBezierPath.cgPath // The important part
    }
}

请注意,单个形状图层中不能有不同颜色的线条。一个形状图层只能包含一个路径,它使用单一的笔触颜色和单一的填充颜色来绘制整个路径。 (描边颜色和填充颜色可以不同,但​​整个路径将使用相同的颜色。)

【讨论】:

  • 收件人:Duncan C... 添加了请求的代码。抱歉疏忽。
  • 很棒的答案,邓肯!易于理解并且有效。感谢您付出如此清晰的努力。你一定是老师。 :-)
  • 很高兴我能帮上忙。赞成票欣然接受。 :)
【解决方案2】:

与其尝试从路径中删除所有点并重用路径对象,不如构造一条新路径。

一旦绘制了路径,它就是上下文的一部分,您无法通过更改路径来删除或更改图形。如果您想从绘图中删除某些内容,则必须擦除上下文(或其中的一部分)并在已擦除的位置重新绘制。

通常你会擦除所有内容并重新绘制。

您也不应该在 viewDidLoad 中绘图,此时视图甚至可能没有连接到绘图表面。绘图应该由视图完成,而不是视图控制器。

【讨论】:

  • OP 没有将他的路径绘制到上下文中。他正在创建一个 CAShapeLayer 并将路径安装到形状层中。假设他将该形状图层添加为他的视图图层之一的子图层,系统会自动渲染路径。这是在 iOS 中绘制的一种非常有效的方式。它利用了 GPU 和平铺渲染引擎。
  • 只有当您想要额外层的额外开销时,这才是正确的。图层保留的位图不是免费的。视图已经有一个图层,并且可以直接在视图的图层中轻松绘制形状。虽然可以快速渲染附加层,但它是一个单独的绘图,所以现在您必须渲染两层而不是一层。
  • 有问题的上下文当然属于该层的后备存储......但是您是正确的,系统正在渲染该层中的路径。
  • 与计算机科学中的许多事情一样,这是一种权衡。在这种情况下,内存与计算性能。实现draw(rect:) 并绘制到视图的上下文中较慢。添加层更快,但会增加内存。在现代设备上,内存压力比以前小了很多,因此额外的内存成本通常是值得的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2022-07-07
  • 1970-01-01
相关资源
最近更新 更多