【问题标题】:iOS drawing in CALayers drawInContext is either pixelated or blurry on retinaCALayers drawInContext 中的 iOS 绘图在视网膜上像素化或模糊
【发布时间】:2014-11-02 23:28:05
【问题描述】:

我有一个自定义的UIView,它会在覆盖中绘制一些东西

- (void)drawRect:(CGRect)rect

这很好用,并且在视网膜屏幕上提供了清晰的结果。

但是,现在我想让绘图所基于的属性可动画化。似乎只能在CALayer 上创建动画属性,所以我没有在UIView 中进行绘图,而是创建了一个自定义CALayer 子类并在内部进行绘图

- (void) drawInContext:(CGContextRef)ctx

我在此函数中使用的绘图代码与在自定义 UIViewdrawRect 函数中使用的绘图代码几乎完全相同。

结果看起来一样 - 但是,它不是视网膜分辨率,而是像素化(大方形像素)

如果我放了

self.contentsScale = [UIScreen mainScreen].scale;

在我的drawInContext 实现开始时,我得到的不是像素化结果,而是模糊的结果(好像渲染仍然以非视网膜分辨率执行,然后放大到视网膜分辨率)。

CALayers drawInContext 中渲染锐利视网膜路径的正确方法是什么?

这里是一些截图(蓝线是有问题的自定义绘图的一部分。黄色部分只是一张图片)

在自定义 UIView 的 drawRect 内绘制:

在自定义 CALayer 的 drawInContext 内绘制:

在自定义 CALayer 的 drawInContext 内绘制,首先设置 self.contentScale

为了完整起见,这里是(精简版的)绘图代码:

//if drawing inside custom UIView sublcass:
- (void)drawRect:(CGRect)rect
{
    CGContextRef currenctContext = UIGraphicsGetCurrentContext();
    [[UIColor blackColor] set];

    CGContextSetLineWidth(currenctContext, _lineWidth);
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound);

    CGContextMoveToPoint(currenctContext,x1, y1);
    CGContextAddLineToPoint(currenctContext,x2, y2);
    CGContextStrokePath(currenctContext);
}

//if drawing inside custom CALayer subclass:
- (void) drawInContext:(CGContextRef)ctx {
{
    //self.contentsScale = [UIScreen mainScreen].scale;

    CGContextRef currenctContext = ctx;
    CGContextSetStrokeColorWithColor(currenctContext, [UIColor blackColor].CGColor);

    CGContextSetLineWidth(currenctContext, _lineWidth);
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound);

    CGContextMoveToPoint(currenctContext,x1, y1);
    CGContextAddLineToPoint(currenctContext,x2, y2);
    CGContextStrokePath(currenctContext);
}

重申我想要实现的目标:我想要实现与UIView 方法中相同的清晰视网膜渲染,但在CALayer 中渲染时

【问题讨论】:

  • 在retina显示中,需要将高和宽乘以2。
  • 不,屏幕上的大小和位置是正确的
  • 感谢您的帮助,但我认为您在这里没有正确理解我的问题
  • 如果把self.contentsScale = [UIScreen mainScreen].scale移到层初始化方法呢?
  • 你解决过这个问题吗?我有完全相同的问题,使用 shouldRasterize 和设置 rasterizationScale 没有效果。

标签: ios core-graphics calayer retina


【解决方案1】:

这里的问题很可能是 contentScale;请注意,如果您通过覆盖其layerClass 函数将其分配给自定义视图,则图层的内容比例可能会被重置。可能还有其他一些情况也会发生这种情况。为安全起见,请仅在将图层添加到视图后设置内容比例。

尝试在自定义视图的 init 方法中将主屏幕的比例分配给自定义层。在 Swift 3 中看起来像这样:

layer.contentsScale = UIScreen.mainScreen().scale

或者,在 Swift 4 中:

layer.contentsScale = UIScreen.main.scale

【讨论】:

  • 完美解决了像素化问题
  • 问题解决了,谢谢!斯威夫特 5 2021
【解决方案2】:

将图层添加到其超级图层之后。将 shouldRasterize 设置为 YES ,将 contentsScale 和 resterizatioinScale 设置为屏幕比例:

[self.progressView.layer addSublayer:self.progressLayer];
self.progressLayer.shouldRasterize = YES;
self.progressLayer.contentsScale = kScreenScale;
self.progressLayer.rasterizationScale = kScreenScale;

CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"progress"];// progress is a customized property of progressLayer
animate.duration = 1.5;
animate.beginTime = 0;
animate.fromValue = @0;
animate.toValue = @1;
animate.fillMode = kCAFillModeForwards;
animate.removedOnCompletion = NO;
animate.repeatCount = HUGE_VALF;
[self.progressLayer addAnimation:animate forKey:@"progressAnimation"];

【讨论】:

    【解决方案3】:

    你在层中使用shouldRasterize = YES 吗?尝试在 CALayer 子类中绘制,但将 rasterizationScale 设置为屏幕的比例。

    【讨论】:

    • @AndresCanella 您在哪个设备上使用 4.0 进行光栅化缩放?
    • @Crashalot 我最终在 i6 上使用了屏幕比例 * 2.0。我在 4.0 上失去了脆度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    相关资源
    最近更新 更多