CAShapeLayer not updating when changing path
Asked Answered
A

2

5

I'm using a CAShapeLayer. I'm trying to make it so that its path changes whenever a mouse event occurs. For example, when a mouse down event occurs, a path is appended to a CGMutableRefPath and then then the shape layer's path is set to it.

The problem: When I set the CAShapeLayer path with a new path, the display is not updated with a new path unless I do . How do I tell the system that the shape layer's path has changed and to redraw itself?

Note: When I create a copy of the mutable path and pass it along, it works, but doing a copy every time is not performant and causes my computer to slow down when there are lots of paths.

CGMutablePathRef paths = CGPathCreateMutable();
CAShapeLayer *shapeLayer = [CAShapeLayer layer];

- (void)mouseDown:(NSEvent *)event {
    CGPathAddEllipseInRect(paths, nil, rect);
    self.shapeLayer.path = paths; // Works once, but subsequent calls do nothing
    self.shapeLayer.path = CGPathCreateCopy(paths); // Works, but super slow
}
Assurbanipal answered 2/8, 2013 at 20:20 Comment(0)
A
9

Call [self.shapeLayer didChangeValueForKey:@"path"] to force the layer to redraw itself.

Assurbanipal answered 3/8, 2013 at 11:52 Comment(1)
Ah, sounds like setPath: sees that the pointer you're passing is the same as the one the property already has, and doesn't look to see if the path itself has changed (which would be expensive). Your work-around simply forces the action that would have occurred had you passed a different pointer. (Obviously, CAShapeLayer is not copying the path, even if it's mutable, but also not updating automatically if that path is changed, which was my own question that led me to this post.)Promisee
Z
1

Make sure your path is a valid one i.e. it has valid vertices and fill etc. Such as (this is just an example of a 200 X 200 rect filled with color, you may use your own):

 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextAddPath(context, paths);
 CGPathAddRect(paths, NULL, CGRectMake(100.0, 100.0, 200.0, 200.0)); // generates a warning specified later
 CGContextFillPath(context);

After updating path, call

[shapeLayer setNeedsDisplay]

or

[shapeLayer setNeedsLayout]

or both.

Zeph answered 2/8, 2013 at 20:23 Comment(3)
Thanks, but I've tried calling setNeedsDisplay and setNeedsLayout on the shape layer, but it has no effect. Pretty sure my paths are all valid. They are all circles with R=50, but different origins. What does work is creating a copy of paths and setting to it. Example: self.shapeLayer.path = CGPathCreateCopy(paths);. But doing a copy over time causes my computer to bog down.Assurbanipal
Figured it out. I had to call [self.shapeLayer didChangeValueForKey:@"path"] to get the layer to re-render itself. Thanks for the help though.Assurbanipal
If it helped mark is at right (checkmark) - it will help you get quicker answers in future.Zeph

© 2022 - 2024 — McMap. All rights reserved.