gpt4 book ai didi

ios - 如何用 CAShapeLayer 和 UIBezierPath 绘制一个平滑的圆?

转载 作者:IT王子 更新时间:2023-10-29 07:32:03 24 4
gpt4 key购买 nike

我试图通过使用 CAShapeLayer 并在其上设置圆形路径来绘制描边圆。但是,与使用 borderRadius 或直接在 CGContextRef 中绘制路径相比,此方法在呈现到屏幕时始终不太准确。

以下是所有三种方法的结果:enter image description here

请注意,第三个渲染效果很差,尤其是在顶部和底部的笔划内。

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 实现相同):

enter image description here

在第二个示例中,您会看到问题所在。我使用红色的 CAShapeLayer 绘制了一次,然后在顶部使用相同路径的 drawRect: 实现再次绘制,但为绿色。请注意,您可以从下面的红色圆圈中看到更多的不一致性和更多的出血。它显然是以一种不同的(而且更糟糕的)方式绘制的。

enter image description here

最佳答案

谁知道画圆有这么多方法?

TL;DR: If you want to use CAShapeLayer and still get smooth circles, you'll need to use shouldRasterize and rasterizationScale carefully.

原创

enter image description here

这是您的原始 CAShapeLayer 以及与 drawRect 版本的差异。我用配备 Retina 显示屏的 iPad Mini 截屏,然后在 Photoshop 中对其进行处理,并将其放大到 200%。您可以清楚地看到,CAShapeLayer 版本有明显的差异,尤其是在左右边缘(差异中最暗的像素)。

按屏幕比例栅格化

enter image description here

让我们按屏幕比例进行栅格化,在 Retina 设备上应该是 2.0。添加此代码:

layer.rasterizationScale = [UIScreen mainScreen].scale;
layer.shouldRasterize = YES;

请注意,即使在 Retina 设备上,rasterizationScale 默认为 1.0,这也是默认 shouldRasterize 模糊的原因。

圆圈现在更平滑了一些,但坏点(差异中最暗的像素)已经移动到顶部和底部边缘。并不比没有光栅化好多少!

以 2 倍屏幕比例栅格化

enter image description here

layer.rasterizationScale = 2.0 * [UIScreen mainScreen].scale;
layer.shouldRasterize = YES;

这会以 2 倍屏幕比例栅格化路径,或者在视网膜设备上高达 4.0

圆圈现在明显更平滑,差异更轻且分布均匀。

我还在 Instruments: Core Animation 中运行了它,但在 Core Animation 调试选项中没有发现任何重大差异。然而,它可能会更慢,因为它正在缩小比例,而不仅仅是将屏幕外位图显示到屏幕上。您可能还需要在设置动画时临时设置 shouldRasterize = NO

什么不起作用

  • 自行设置 shouldRasterize = YES在 Retina 设备上,这看起来很模糊,因为 rasterizationScale != screenScale

  • 设置 contentScale = screenScale因为 CAShapeLayer 不会绘制到 contents 中,无论是不是光栅化,这不会影响再现。

感谢 Jay Hollywood 的 Humaan ,第一个向我指出这一点的敏锐平面设计师。

关于ios - 如何用 CAShapeLayer 和 UIBezierPath 绘制一个平滑的圆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24316705/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com