Home > Software engineering >  Can't get Swift UIBezierPath plot to remove and then update
Can't get Swift UIBezierPath plot to remove and then update

Time:10-29

In my app, viewdidLoad() uses UIBezierPath to display green UIBezierPath plotted line.
But later in the program, an event callback uses same UIBezierPath to removeAllPoints and display red line next to green one.
But, all it does is turn the green line to red, at same position.

Ultimately, I want to use UIBezierPath to each second show an ever-changing, multi-line plot -- that is: remove previous multi-line plot and show updated multi-line plot, every second.

CODE THAT SHOWS GREEN LINE...................

    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...
}

CODE THAT IS SUPPOSED TO SHOW RED LINE NEXT TO IT.................
(but actually turns initial green line to red, at same position -- no 2nd line next to first)

...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
        }
    }

CodePudding user response:

Rather than trying to remove all the points from a path and reuse the path object, just construct a new path.

Once a path has been drawn, it’s part of the context, you can’t remove or change the graphic by changing the path. If you want to remove something from the drawing you have to erase the context (or part of it) and redraw where you’ve erased.

Usually you erase everything and redraw if.

You also should not be drawing in viewDidLoad, the view might not even be connected to a drawing surface at that point. Drawing should be done by the view, not the view controller.

CodePudding user response:

You don't show the code that installs your path in your shape layer, or the code that installs your shape layer as a sublayer of your view controller's view. You should show that code so that we can see what you're doing. You should also show the code for your init_app_display() function.

I assume that somewhere you have code that says:

sensor_plot_CAShapeLayer.path = self.sensor_plot_UIBezierPath.cgPath

and code that does something like

view.layer.addSublayer(sensor_plot_CAShapeLayer)

You seem to be under the impression that setting a CAShapeLayer's path to a specific bezier path links the shape layer to that path, and updating the path updates the shape layer. It doesn't work that way. After changing your path, you need to install the new path into your shape layer.

You could change your display_plot_update() function like this:

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
        sensor_plot_CAShapeLayer.path = newPath.cgPath // The important part
    }
}

That would move the line to your new coordinates and make it red.

If you want to add a second line next to the first, then write your `display_plot_update()~ function like this:

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
    }
}

Note that you can't have lines of different colors in a single shape layer. A shape layer can only contain a single path, and it draws the entire path using a single stroke color and a single fill color. (The stroke color and the fill color can be different, but the entire path will use those same colors.)

  • Related