ios 如何使 CATextLayer 中的文本清晰

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3815443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:48:46  来源:igfitidea点击:

How to get text in a CATextLayer to be clear

textioscore-animationcalayer

提问by Steve

I've made a CALayerwith an added CATextLayerand the text comes out blurry. In the docs, they talk about "sub-pixel antialiasing", but that doesn't mean much to me. Anyone have a code snippet that makes a CATextLayerwith a bit of text that is clear?

我已经CALayer添加了一个CATextLayer,但文本变得模糊。在文档中,他们谈论“亚像素抗锯齿”,但这对我来说意义不大。任何人都有一个代码片段,可以制作一些CATextLayer清晰的文本?

Here's the text from Apple's documentation:

以下是 Apple 文档中的文字:

Note: CATextLayer disables sub-pixel antialiasing when rendering text. Text can only be drawn using sub-pixel antialiasing when it is composited into an existing opaque background at the same time that it's rasterized. There is no way to draw subpixel-antialiased text by itself, whether into an image or a layer, separately in advance of having the background pixels to weave the text pixels into. Setting the opacity property of the layer to YES does not change the rendering mode.

注意: CATextLayer 在渲染文本时禁用子像素抗锯齿。当文本在光栅化的同时合成到现有的不透明背景中时,只能使用子像素抗锯齿来绘制文本。在将文本像素编织到背景像素之前,无法单独绘制子像素抗锯齿文本,无论是图像还是图层。将图层的 opacity 属性设置为 YES 不会更改渲染模式。

The second sentence implies that one can get good looking text if one compositesit into an existing opaque background at the same time that it's rasterized.That's great, but how do I composite it and how do you give it an opaque background and how do you rasterize it?

第二句话暗示,如果将composites其转换为一个,则可以获得漂亮的文本。existing opaque background at the same time that it's rasterized.那太好了,但是我如何合成它,如何给它一个不透明的背景以及如何对其进行光栅化?

The code they use in their example of a Kiosk Menu is as such: (It's OS X, not iOS, but I assume it works!)

他们在 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 

Thanks!

谢谢!



EDIT: Adding the code that I actually used that resulted in blurry text. It's from a related question I posted about adding a UILabelrather than a CATextLayerbut getting a black box instead. http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box

编辑:添加我实际使用的导致文本模糊的代码。它来自我发布的一个相关问题,关于添加一个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);


EDIT 2: See my answer below for how this got solved. sbg.

编辑 2:有关如何解决此问题,请参阅下面的答案。某人。

回答by Steve

Short answer — You need to set the contents scaling:

简短回答 - 您需要设置内容缩放:

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


A while ago I learned that when you have custom drawing code, you have to check for the retina display and scale your graphics accordingly. UIKittakes care of most of this, including font scaling.

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

Not so with CATextLayer.

不是这样 CATextLayer.

My blurriness came from having a .zPositionthat was not zero, that is, I had a transform applied to my parent layer. By setting this to zero, the blurriness went away, and was replaced by serious pixelation.

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

After searching high and low, I found that you can set .contentsScalefor a CATextLayerand you can set it to [[UIScreen mainScreen] scale]to match the screen resolution. (I assume this works for non-retina, but I haven't checked - too tired)

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

After including this for my CATextLayerthe text became crisp. Note - it's not necessary for the parent layer.

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

And the blurriness? It comes back when you're rotating in 3D, but you don't notice it because the text starts out clear and while it's in motion, you can't tell.

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

Problem solved!

问题解决了!

回答by Suragch

Swift

迅速

Set the text layer to use the same scale as the screen.

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

textLayer.contentsScale = UIScreen.main.scale

Before:

前:

enter image description here

在此处输入图片说明

After:

后:

enter image description here

在此处输入图片说明

回答by Matt Long

First off I wanted to point out that you've tagged your question with iOS, but constraint managers are only available on OSX, so I'm not sure how you're getting this to work unless you've been able to link against it in the simulator somehow. On the device, this functionality is not available.

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

Next, I'll just point out that I create CATextLayers often and never have the blurring problem you're referring to so I know it can be done. In a nutshell this blurring occurs because you are not positioning your layer on the whole pixel. Remember that when you set the position of a layer, you use a float values for the x and y. If those values have numbers after the decimal, the layer will not be positioned on the whole pixel and will therefore give this blurring effect--the degree of which depending upon the actual values. To test this, just create a CATextLayer and explicitly add it to the layer tree ensuring that your position parameter is on a whole pixel. For example:

接下来,我将指出我经常创建 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];

If your text is still blurry, then there is something else wrong. Blurred text on your text layer is an artifact of incorrectly written code and not an intended capability of the layer. When adding your layers to a parent layer, you can just coerce the x and y values to the nearest whole pixel and it should solve your blurring problem.

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

回答by Gabe

Before setting shouldRasterize, you should:

在设置 shouldRasterize 之前,您应该:

  1. set the rasterizationScale of the base layer you are going to rasterize
  2. set the contentsScale property of any CATextLayers and possibly other types of layers(it never hurts to do it)
  1. 设置要光栅化的基础层的 rasterizationScale
  2. 设置任何 CATextLayers 和可能的其他类型图层的 contentsScale 属性(这样做不会有什么坏处)

If you don't do #1, then the retina version of sub layers will look blurry, even for normal CALayers.

如果你不做 #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];
}

回答by MoDJ

You should do 2 things, the first was mentioned above:

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

Extend CATextLayer and set the opaque and contentsScale properties to properly support retina display, then render with anti aliasing enabled for text.

扩展 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];
}

回答by james_alvarez

If you came searching here for a similar issue for a CATextLayer in OSX, after much wall head banging, I got the sharp clear text by doing:

如果您来这里搜索 OSX 中 CATextLayer 的类似问题,经过多次敲击墙壁后,我通过执行以下操作获得了清晰的文本:

text_layer.contentsScale = self.window!.backingScaleFactor

(I also set the views background layer contentsScale to be the same).

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

回答by Alejandro Luengo

This is faster and easier: you just need to set contentsScale

这更快更容易:您只需要设置 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];