如何在Cocoa中使用两种交替颜色对虚线CGPath进行描边?

3
我想要用两种交替的颜色(例如黑色和白色,类似于 Preview.app 的选择框)描绘一个 CAShapeLayer 的路径。我不确定如何做到这一点,或者使用 Quartz 是否能够实现。
我已经设置了 CAShapeLayer 的白色边框,并将路径属性设置为虚线黑色线条。我希望这样可以呈现出黑白相间的虚线效果。然而,似乎路径是先绘制的,然后在其上方描绘了边框,如下图所示(毛发属于我的猫): CAShapeLayer with white border and black stroked path, the path is drawn first followed yb the border. 有人能提供更好的方法或让它正常工作的方法吗?
代码:
// Stroke a white border
[shapeLayer setFrame:shapeRect];
[shapeLayer setBorderColor:[[NSColor whiteColor] CGColor]];
[shapeLayer setBorderWidth:1.0];

// Stroked a black dash path (along the border)
// and fill shape with clear colour
[shapeLayer setFillColor:[[NSColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[[NSColor blackColor] CGColor]];
[shapeLayer setLineWidth:1.0];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:
 [NSArray arrayWithObjects:[NSNumber numberWithInt:5],
  [NSNumber numberWithInt:5],
  nil]];

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, shapeLayer.bounds);
[shapeLayer setPath:path];
CGPathRelease(path);
2个回答

2

我认为这种方法存在两个问题(混合图层边框和形状描边):

  1. 边框位于边界内部,但描边是从路径中心开始的。
  2. 路径描边之后再绘制边框。

您可以通过将路径插入半个描边宽度来解决第一个问题。

CGFloat halfWidth = 1.0/2.0;
CGPathAddRect(path, NULL, CGRectInset(shapeLayer.bounds, halfWidth, halfWidth));

然而,边框仍将绘制在形状上方(至少我不知道如何更改顺序)。
我认为最简单的解决方案是在同一个容器层中有两个形状层。容器将用于更改帧,两个层将用于绘图。
底部层将具有白色描边(无虚线模式),顶部层将具有虚线黑色描边。由于两个形状都具有相同的路径,因此它看起来像是黑白虚线图案。
以这种方式进行操作也适用于任何形状。

谢谢。所以在你的意见中,两个层是唯一的选择?我想避免那种感觉像是一个hack的做法! - Daniel Farrell
@boyfarrell 要么使用两个图层,要么进行自定义渲染。我个人会选择两个图层。我假设你在屏幕上只有几个(如果不是只有一个)选择,因此不应该有任何性能影响,并且代码不太复杂,可以很好地封装在它自己的类中(带有两个私有子层)。 - David Rönnqvist
是的,那是很好的建议,谢谢。我计划创建一个CAShapeLayer子类(比如说“HostingShapeLayer”),它具有foregroundLayer属性。该属性将前景层作为子层添加到托管层中。托管层还沿边框描绘了白色路径。子层可以做成黑色虚线。听起来像是合理的设计吗?或者你会选择其他方案? - Daniel Farrell

0

你尝试使用lineDashPhase属性了吗?使用它,你可以先显示黑色虚线,然后改变颜色和lineDashPhase - 显示白色,覆盖相同的路径。


谢谢。我已经在使用它了(用于不同的目的),来实现蚂蚁行进效果,http://www.cimgf.com/2009/10/20/marching-ants-with-core-animation。我不确定你的实现方式是如何工作的?因为只有一个路径属性和一个lineDashPhase属性,所以我不明白如何绘制两条线。 - Daniel Farrell
抱歉,我漏掉了那个点。不过你可以添加两个CAShapeLayers,但我认为这不是一个好的方法。 - Nickolay Olshevsky
1
@NickolayOlshevsky 你会做什么呢? - David Rönnqvist

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