【发布时间】:2014-08-10 14:06:43
【问题描述】:
我正在尝试通过使用 CAShapeLayer 并在其上设置圆形路径来绘制描边圆。但是,这种方法在渲染到屏幕时始终不如使用borderRadius 或直接在CGContextRef 中绘制路径准确。
以下是所有三种方法的结果:
请注意,第三个渲染效果不佳,尤其是在顶部和底部的笔划内。
我已经将contentsScale 属性设置为[UIScreen mainScreen].scale。
这是我为这三个圆圈绘制的代码。使 CAShapeLayer 平滑绘制缺少什么?
@interface BCViewController ()
@end
@interface BCDrawingView : UIView
@end
@implementation BCDrawingView
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
self.backgroundColor = nil;
self.opaque = YES;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
[[UIColor whiteColor] setFill];
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), NULL);
[[UIColor redColor] setStroke];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1);
[[UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.bounds, 4, 4)] stroke];
}
@end
@interface BCShapeView : UIView
@end
@implementation BCShapeView
+ (Class)layerClass
{
return [CAShapeLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
self.backgroundColor = nil;
CAShapeLayer *layer = (id)self.layer;
layer.lineWidth = 1;
layer.fillColor = NULL;
layer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.bounds, 4, 4)].CGPath;
layer.strokeColor = [UIColor redColor].CGColor;
layer.contentsScale = [UIScreen mainScreen].scale;
layer.shouldRasterize = NO;
}
return self;
}
@end
@implementation BCViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *borderView = [[UIView alloc] initWithFrame:CGRectMake(24, 104, 36, 36)];
borderView.layer.borderColor = [UIColor redColor].CGColor;
borderView.layer.borderWidth = 1;
borderView.layer.cornerRadius = 18;
[self.view addSubview:borderView];
BCDrawingView *drawingView = [[BCDrawingView alloc] initWithFrame:CGRectMake(20, 40, 44, 44)];
[self.view addSubview:drawingView];
BCShapeView *shapeView = [[BCShapeView alloc] initWithFrame:CGRectMake(20, 160, 44, 44)];
[self.view addSubview:shapeView];
UILabel *borderLabel = [UILabel new];
borderLabel.text = @"CALayer borderRadius";
[borderLabel sizeToFit];
borderLabel.center = CGPointMake(borderView.center.x + 26 + borderLabel.bounds.size.width/2.0, borderView.center.y);
[self.view addSubview:borderLabel];
UILabel *drawingLabel = [UILabel new];
drawingLabel.text = @"drawRect: UIBezierPath";
[drawingLabel sizeToFit];
drawingLabel.center = CGPointMake(drawingView.center.x + 26 + drawingLabel.bounds.size.width/2.0, drawingView.center.y);
[self.view addSubview:drawingLabel];
UILabel *shapeLabel = [UILabel new];
shapeLabel.text = @"CAShapeLayer UIBezierPath";
[shapeLabel sizeToFit];
shapeLabel.center = CGPointMake(shapeView.center.x + 26 + shapeLabel.bounds.size.width/2.0, shapeView.center.y);
[self.view addSubview:shapeLabel];
}
@end
编辑:对于那些看不出区别的人,我在彼此的顶部画了圆圈并放大:
这里我用drawRect: 画了一个红色圆圈,然后在上面用绿色再次用drawRect: 画了一个相同的圆圈。注意红色的有限出血。这两个圆圈都是“平滑的”(与cornerRadius 实现相同):
在第二个示例中,您将看到问题所在。我曾经使用红色的CAShapeLayer 绘制过一次,然后再次在顶部使用相同路径的drawRect: 实现,但使用绿色。请注意,您可以看到更多的不一致,下面的红色圆圈有更多的出血。它显然是以不同(更糟)的方式绘制的。
【问题讨论】:
-
不确定它是否与您的图像捕获有关,但上面的三个圆圈 - 至少在我看来 - 完全一样。
-
在这一行中:
[UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.bounds, 4, 4)]self.bound保存点(不是像素),因此从技术上讲,您正在创建一个非视网膜大小的曲线。如果将该尺寸乘以[UIScreen mainScreen].scale值,您的椭圆在视网膜屏幕上将非常平滑。 -
@MaxMacLeod 检查我的编辑是否有差异。
-
@holex 这只是一个更小的圆圈。我的两个实现都使用相同的路径,一个看起来不错,另一个不好看。
-
在文档中,它说光栅化有利于速度而不是质量。可能是您看到了不精确插值/抗锯齿的伪影。
标签: ios uikit core-graphics calayer cashapelayer