【问题标题】:How to get text in a CATextLayer to be clear如何使 CATextLayer 中的文本清晰
【发布时间】:2011-04-18 10:39:27
【问题描述】:

我创建了一个CALayer 并添加了CATextLayer,文本变得模糊。在文档中,他们谈论“亚像素抗锯齿”,但这对我来说意义不大。任何人都有一个代码 sn-p 可以生成 CATextLayer 并带有一些清晰的文本?

以下是 Apple 文档中的文字:

注意:CATextLayer 在渲染文本时禁用亚像素抗锯齿。 文本只能使用亚像素抗锯齿绘制 同时合成到现有的不透明背景中 它被光栅化了。无法通过以下方式绘制子像素抗锯齿文本 本身,无论是成图像还是图层,分别提前 有背景像素来编织文本像素。环境 图层的 opacity 属性为 YES 不会改变渲染 模式。

第二句话暗示如果将composites 转换为existing opaque background at the same time that it's rasterized. 可以得到好看的文本,这很好,但是我如何合成它以及如何给它一个不透明的背景以及如何光栅化它?

他们在 Kiosk 菜单示例中使用的代码如下:(它是 OS X,不是 iOS,但我认为它可以工作!)

NSInteger i;
for (i=0;i<[names count];i++) {
    CATextLayer *menuItemLayer=[CATextLayer layer];
    menuItemLayer.string=[self.names objectAtIndex:i];
    menuItemLayer.font=@"Lucida-Grande";
    menuItemLayer.fontSize=fontSize;
    menuItemLayer.foregroundColor=whiteColor;
    [menuItemLayer addConstraint:[CAConstraint
         constraintWithAttribute:kCAConstraintMaxY
                      relativeTo:@"superlayer"
                       attribute:kCAConstraintMaxY
                          offset:-(i*height+spacing+initialOffset)]];
    [menuItemLayer addConstraint:[CAConstraint
         constraintWithAttribute:kCAConstraintMidX
                      relativeTo:@"superlayer"
                       attribute:kCAConstraintMidX]];
    [self.menuLayer addSublayer:menuItemLayer];
} // end of for loop 

谢谢!


编辑:添加我实际使用的导致文本模糊的代码。这是来自我发布的一个相关问题,即添加 UILabel 而不是 CATextLayer 而是得到一个黑匣子。 http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box

CATextLayer* upperOperator = [[CATextLayer alloc] init];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGFloat components1[4] = {1.0, 1.0, 1.0, 1.0};
CGColorRef almostWhite = CGColorCreate(space,components1);
CGFloat components2[4] = {0.0, 0.0, 0.0, 1.0};
CGColorRef almostBlack = CGColorCreate(space,components2);
CGColorSpaceRelease(space);
upperOperator.string = [NSString stringWithFormat:@"13"];
upperOperator.bounds = CGRectMake(0, 0, 100, 50);
upperOperator.foregroundColor = almostBlack;
upperOperator.backgroundColor = almostWhite;
upperOperator.position = CGPointMake(50.0, 25.0);
upperOperator.font = @"Helvetica-Bold";
upperOperator.fontSize = 48.0f;
upperOperator.borderColor = [UIColor redColor].CGColor;
upperOperator.borderWidth = 1;
upperOperator.alignmentMode = kCAAlignmentCenter;
[card addSublayer:upperOperator];
[upperOperator release];
CGColorRelease(almostWhite);
CGColorRelease(almostBlack);

编辑 2:请参阅下面的答案以了解如何解决。 sbg.

【问题讨论】:

标签: text ios core-animation calayer


【解决方案1】:

首先,我想指出您已使用 iOS 标记了您的问题,但约束管理器仅在 OSX 上可用,所以我不确定您如何使其工作,除非您能够以某种方式在模拟器中链接它。在设备上,此功能不可用。

接下来,我要指出的是,我经常创建 CATextLayers,从来没有遇到过您所指的模糊问题,所以我知道可以做到。简而言之,发生这种模糊是因为您没有将图层定位在整个像素上。请记住,当您设置图层的位置时,您对 x 和 y 使用浮点值。如果这些值在小数点后有数字,则图层将不会定位在整个像素上,因此会产生这种模糊效果——其程度取决于实际值。要对此进行测试,只需创建一个 CATextLayer 并将其显式添加到层树中,以确保您的位置参数位于整个像素上。例如:

CATextLayer *textLayer = [CATextLayer layer];
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)];
[textLayer setPosition:CGPointMake(200.0f, 100.0f)];
[textLayer setString:@"Hello World!"];

[[self menuLayer] addSublayer:textLayer];

如果您的文字仍然模糊,那么还有其他问题。文本图层上的模糊文本是错误编写代码的产物,而不是图层的预期功能。将图层添加到父图层时,您可以将 x 和 y 值强制为最近的整个像素,它应该可以解决您的模糊问题。

【讨论】:

    【解决方案2】:

    简答——您需要设置内容缩放:

    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    

    不久前我了解到,当您有自定义绘图代码时,您必须检查视网膜显示并相应地缩放您的图形。 UIKit 负责大部分工作,包括字体缩放。

    CATextLayer. 不是这样

    我的模糊来自.zPosition 不为零,也就是说,我对父层应用了一个变换。通过将此设置为零,模糊消失了,取而代之的是严重的像素化。

    高低搜索后发现可以将.contentsScale设置为CATextLayer,也可以设置为[[UIScreen mainScreen] scale]来匹配屏幕分辨率。 (我认为这适用于非视网膜,但我还没有检查 - 太累了)

    在我的CATextLayer 包含此内容后,文本变得清晰。注意 - 父层不需要。

    那么模糊呢?当您在 3D 中旋转时,它会返回,但您不会注意到它,因为文本开始时是清晰的,而当它在运动时,您无法分辨。

    问题解决了!

    【讨论】:

    • 这是简短的答案:textLayer.contentScale = [[UIScreen mainScreen] scale]; BTW,我也喜欢长答案:)
    • 这适用于任何以编程方式创建的 CALayer。例如,如果您发现绘制到 CALayer 中的图像在视网膜显示屏上不清晰,则很可能这就是问题和解决方案。
    • 更正_textLayer.contentsScale = [[UIScreen mainScreen] scale]; 你少了一个“s” ;)
    • 这对我不起作用。我通过 AVVideoCompositionCoreAnimationTool 将 CATextLayer 添加到视频 (AVFoundation/AVMutableComposition)。文本仍然有别名。
    • mac osx 中没有缩放选项
    【解决方案3】:

    在设置 shouldRasterize 之前,您应该:

    1. 设置要栅格化的基础图层的 rasterizationScale
    2. 设置任何 CATextLayers 和可能的其他类型图层的 contentsScale 属性(这样做永远不会有坏处)

    如果你不做#1,那么视网膜版本的子层会看起来很模糊,即使是普通的 CALayers。

    - (void)viewDidLoad {
      [super viewDidLoad];
    
      CALayer *mainLayer = [[self view] layer];
      [mainLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
    
      CATextLayer *messageLayer = [CATextLayer layer];
      [messageLayer setForegroundColor:[[UIColor blackColor] CGColor]];
      [messageLayer setContentsScale:[[UIScreen mainScreen] scale]];
      [messageLayer setFrame:CGRectMake(50, 170, 250, 50)];
      [messageLayer setString:(id)@"asdfasd"];
    
      [mainLayer addSublayer:messageLayer];
    
      [mainLayer setShouldRasterize:YES];
    }
    

    【讨论】:

      【解决方案4】:

      你应该做两件事,第一件事是上面提到的:

      扩展 CATextLayer 并设置 opaque 和 contentsScale 属性以正确支持视网膜显示,然后为文本启用抗锯齿渲染。

      + (TextActionLayer*) layer
      {
        TextActionLayer *layer = [[TextActionLayer alloc] init];
        layer.opaque = TRUE;
        CGFloat scale = [[UIScreen mainScreen] scale];
        layer.contentsScale = scale;
        return [layer autorelease];
      }
      
      // Render after enabling with anti aliasing for text
      
      - (void)drawInContext:(CGContextRef)ctx
      {
          CGRect bounds = self.bounds;
          CGContextSetFillColorWithColor(ctx, self.backgroundColor);
          CGContextFillRect(ctx, bounds);
          CGContextSetShouldSmoothFonts(ctx, TRUE);
          [super drawInContext:ctx];
      }
      

      【讨论】:

        【解决方案5】:

        如果您来这里搜索 OSX 中 CATextLayer 的类似问题,经过多次撞墙后,我得到了清晰的文本:

        text_layer.contentsScale = self.window!.backingScaleFactor
        

        (我还将视图背景层 contentsScale 设置为相同)。

        【讨论】:

          【解决方案6】:

          这样更快更简单:你只需要设置 contentsScale

              CATextLayer *label = [[CATextLayer alloc] init];
              [label setFontSize:15];
              [label setContentsScale:[[UIScreen mainScreen] scale]];
              [label setFrame:CGRectMake(0, 0, 50, 50)];
              [label setString:@"test"];
              [label setAlignmentMode:kCAAlignmentCenter];
              [label setBackgroundColor:[[UIColor clearColor] CGColor]];
              [label setForegroundColor:[[UIColor blackColor] CGColor]];
              [self addSublayer:label];
          

          【讨论】:

            【解决方案7】:

            斯威夫特

            设置文本层使用与屏幕相同的比例。

            textLayer.contentsScale = UIScreen.main.scale
            

            之前:

            之后:

            【讨论】:

            • macOS swift 4.2 版本:(NSScreen.main?.backingScaleFactor)!
            • @roberto,不要强行打开!安全的解决方案是:textLayer.contentsScale = NSScreen.main?.backingScaleFactor ?? textLayer.contentsScale
            猜你喜欢
            • 2013-03-25
            • 2020-08-20
            • 1970-01-01
            • 2019-02-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-26
            相关资源
            最近更新 更多