2010-09-28 5 views
78

He hecho un CALayer con un CATextLayer añadido y el texto sale borroso. En los documentos, hablan de "antialiasing subpíxel", pero eso no significa mucho para mí. ¿Alguien tiene un fragmento de código que hace un CATextLayer con un poco de texto claro?Cómo obtener texto en un CATextLayer para ser claro

Aquí está el texto de la documentación de Apple:

Nota: CATextLayer desactiva suavizado de subpíxeles al representar texto. El texto solo se puede dibujar utilizando antialiasing subpíxel cuando está compuesto en un fondo opaco existente al mismo tiempo que está rasterizado. No hay forma de dibujar texto antialias de subpixel por en sí mismo, ya sea en una imagen o en una capa, por separado antes de teniendo los píxeles de fondo para entrelazar los píxeles de texto. Estableciendo la propiedad de opacidad de la capa a YES no cambia el modo de representación .

La segunda frase implica que uno puede conseguir buen texto mirando si uno composites en un existing opaque background at the same time that it's rasterized. eso es genial, pero ¿cómo puedo compuesta y cómo le das un fondo opaco y cómo se rasterizar?

El código que utilizan en su ejemplo de un menú Kiosk es como tal: (Es OS X, no IOS, pero supongo que funciona!)

NSInteger i; 
for (i=0;i<[names count];i++) { 
    CATextLayer *menuItemLayer=[CATextLayer layer]; 
    menuItemLayer.string=[self.names objectAtIndex:i]; 
    [email protected]"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 

Gracias!


EDIT: Adición del código que realmente he usado que resultó en el texto borroso. Es de una pregunta relacionada que publiqué sobre cómo agregar un UILabel en lugar de un CATextLayer pero obteniendo un cuadro negro en su lugar. 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: Véase mi respuesta a continuación cómo esta se resolvió. sbg.

+0

esto no responde a su pregunta, pero puede ser relevante para alguien como yo que sólo está buscando para dibujar atribuido texto, de una manera muy similar al uso de UILabel: http://stackoverflow.com/questions/3786528/iphone-ipad-how-exactly-use-nsattributedstrin g – DenNukem

Respuesta

190

Respuesta corta - Es necesario establecer el contenido de escala:

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

Hace un tiempo me enteré de que cuando haya dibujo personalizado de código, usted tiene que comprobar para la visualización de la retina y la escala de los gráficos en consecuencia. UIKit se encarga de la mayor parte de esto, incluido el escalado de fuentes.

No es así con CATextLayer.

Mi visión borrosa procedían de tener un .zPosition que no era cero, es decir, que tenía una transformación aplicarse a mi capa principal. Al establecer esto en cero, la borrosidad desapareció y fue reemplazada por una grave pixelación.

Después de buscar alto y bajo, encontré que puede establecer .contentsScale para CATextLayer y puede configurarlo en [[UIScreen mainScreen] scale] para que coincida con la resolución de pantalla. (Supongo que esto funciona para no retina, pero no lo he comprobado, demasiado cansado)

Después de incluir esto para mi CATextLayer el texto se volvió nítido. Nota: no es necesario para la capa principal.

¿Y la visión borrosa? Vuelve cuando estás girando en 3D, pero no lo notas porque el texto comienza de forma clara y mientras está en movimiento, no puedes distinguirlo.

¡Problema resuelto!

+37

Esta es la respuesta corta: 'textLayer.contentScale = [[UIScreen mainScreen] scale];' BTW, me gustan las respuestas largas también :) – nacho4d

+0

Esto se aplica a cualquier CALayer que se crea mediante programación. Por ejemplo, si observa que las imágenes dibujadas en su CALayer no son nítidas en la pantalla Retina, es probable que este sea el problema y la solución. –

+17

Corrección '_textLayer.contentsScale = [[UIScreen mainScreen] scale];' Te falta una "s";) – Ralphleon

17

En primer lugar, quería señalar que ha etiquetado su pregunta con iOS, pero los administradores de restricciones solo están disponibles en OSX, por lo que no estoy seguro de cómo conseguir que esto funcione a menos que haya sido capaz para unirlo en el simulador de alguna manera. En el dispositivo, esta funcionalidad no está disponible.

A continuación, señalaré que creo CATextLayers a menudo y nunca tengo el problema de borrosidad al que se refiere, así que sé que se puede hacer. En pocas palabras, este desenfoque se produce porque no está colocando su capa en todo el píxel. Recuerde que cuando establece la posición de una capa, usa un valor flotante para xey. Si esos valores tienen números después del decimal, la capa no se colocará en todo el píxel y, por lo tanto, dará este efecto de desenfoque, cuyo grado depende de los valores reales. Para probar esto, solo crea un CATextLayer y explícitamente agrégalo al árbol de capas asegurando que tu parámetro de posición esté en un píxel entero. Por ejemplo:

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]; 

Si su texto sigue estando borroso, hay algo más que está mal. El texto borroso en la capa de texto es un artefacto de código escrito incorrectamente y no una capacidad prevista de la capa.Al agregar las capas a una capa principal, puede forzar los valores de xey en el píxel entero más cercano y resolver su problema de borrosidad.

12

Antes de shouldRasterize, usted debe:

  1. establecer el rasterizationScale de la capa base que se va a rasterizar
  2. establezca la propiedad contentsScale de cualquier CATextLayers y posiblemente otros tipos de capas (nunca está de más hazlo)

Si no haces el n. ° 1, la versión retina de las subcapas se verá borrosa, incluso para CALayers normales.

- (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

Usted debe hacer 2 cosas, la primera se ha mencionado más arriba:

Extender CATextLayer y establecer las propiedades opacas y contentsScale para apoyar adecuadamente pantalla de la retina, luego hacer con anti aliasing habilitado para el texto.

+ (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]; 
} 
0

Si usted vino a buscar aquí por un problema similar para un CATextLayer en OSX, después de mucho golpearse la cabeza contra la pared, que tiene el texto clara y nítida haciendo:

text_layer.contentsScale = self.window!.backingScaleFactor 

(también establecer los puntos de vista contenidos de la capa de fondoScale para ser el mismo).

0

Esto es más rápido y más fácil: sólo tiene que establecer 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]; 
14

Swift

Establecer la capa de texto a utilizar la misma escala que la pantalla.

textLayer.contentsScale = UIScreen.main.scale 

Antes:

enter image description here

Después:

enter image description here

Cuestiones relacionadas